Implemented page recoloring (invert, recolor, bw/contrast, etc..) and small

fixes. Need to find a better place for painting / compositing related
stuff.

svn path=/branches/kpdf_experiments/kdegraphics/kpdf/; revision=360780
This commit is contained in:
Enrico Ros 2004-11-05 18:14:20 +00:00
parent b2db35fb96
commit 3596d8ae9a
6 changed files with 281 additions and 121 deletions

View file

@ -7,7 +7,6 @@ Legend:
(*) - Some parts of this item are already done
In progress on the branch (first item comes first):
-> ADD: reading aids (accessibility) [settings config done while now, 20% done]
-> ADD: click over image allows "save image" (and display rect around image too) [50% done]
-> ADD: viewport changes the right way when clicking links [30% done]
@ -41,6 +40,7 @@ More items (first items will enter 'In progress list' first):
-> wrong zoom buttons order (BR74248) (check consistancy with kdvi/kghostview/.. (not konq))
Done (newest feature comes firts):
-> ADD: reading aids (inverted display, recolor, black/white, ...)
-> FIX: zoom preserved when switching modes and flickerless
-> ADD: Printing as PS instead of as image (Albert)
-> ADD: Remember page on session logout and put the document in it on session restore (Albert)

View file

@ -9,7 +9,7 @@
<x>0</x>
<y>0</y>
<width>320</width>
<height>332</height>
<height>362</height>
</rect>
</property>
<property name="caption">
@ -46,7 +46,10 @@
<cstring>radioNormal</cstring>
</property>
<property name="text">
<string>Normal (default)</string>
<string>&amp;Normal (default)</string>
</property>
<property name="accel">
<string>Alt+N</string>
</property>
<property name="checked">
<bool>true</bool>
@ -140,7 +143,10 @@
<cstring>radioInverted</cstring>
</property>
<property name="text">
<string>Invert colors</string>
<string>&amp;Invert colors</string>
</property>
<property name="accel">
<string>Alt+I</string>
</property>
</widget>
<widget class="QRadioButton">
@ -148,7 +154,10 @@
<cstring>radioRecolor</cstring>
</property>
<property name="text">
<string>Change foreground and background colors</string>
<string>&amp;Change foreground and background colors</string>
</property>
<property name="accel">
<string>Alt+C</string>
</property>
</widget>
<widget class="QLayoutWidget">
@ -281,21 +290,66 @@
<cstring>radioContrast</cstring>
</property>
<property name="text">
<string>Convert to Black and White</string>
<string>Convert to &amp;Black and White</string>
</property>
<property name="accel">
<string></string>
<string>Alt+B</string>
</property>
</widget>
<widget class="QLayoutWidget">
<property name="name">
<cstring>layout3</cstring>
<cstring>layout5</cstring>
</property>
<hbox>
<grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
<spacer>
<widget class="QLabel" row="1" column="1">
<property name="name">
<cstring>textLabel2_2</cstring>
</property>
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Contrast</string>
</property>
</widget>
<spacer row="1" column="3">
<property name="name">
<cstring>spacer10_2</cstring>
</property>
<property name="orientation">
<enum>Horizontal</enum>
</property>
<property name="sizeType">
<enum>Expanding</enum>
</property>
<property name="sizeHint">
<size>
<width>48</width>
<height>21</height>
</size>
</property>
</spacer>
<spacer row="1" column="0">
<property name="name">
<cstring>spacer11_2</cstring>
</property>
<property name="orientation">
<enum>Horizontal</enum>
</property>
<property name="sizeType">
<enum>Fixed</enum>
</property>
<property name="sizeHint">
<size>
<width>16</width>
<height>20</height>
</size>
</property>
</spacer>
<spacer row="0" column="0">
<property name="name">
<cstring>spacer11</cstring>
</property>
@ -312,46 +366,7 @@
</size>
</property>
</spacer>
<widget class="QLabel">
<property name="name">
<cstring>textLabel2</cstring>
</property>
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Contrast:</string>
</property>
</widget>
<widget class="QSlider">
<property name="name">
<cstring>kcfg_BWTreshold</cstring>
</property>
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minValue">
<number>1</number>
</property>
<property name="maxValue">
<number>10</number>
</property>
<property name="value">
<number>5</number>
</property>
<property name="orientation">
<enum>Horizontal</enum>
</property>
</widget>
<spacer>
<spacer row="0" column="3">
<property name="name">
<cstring>spacer10</cstring>
</property>
@ -368,7 +383,62 @@
</size>
</property>
</spacer>
</hbox>
<widget class="QSlider" row="1" column="2">
<property name="name">
<cstring>kcfg_BWContrast</cstring>
</property>
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="orientation">
<enum>Horizontal</enum>
</property>
</widget>
<widget class="QSlider" row="0" column="2">
<property name="name">
<cstring>kcfg_BWThreshold</cstring>
</property>
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="pageStep">
<number>16</number>
</property>
<property name="orientation">
<enum>Horizontal</enum>
</property>
</widget>
<widget class="QLabel" row="0" column="1">
<property name="name">
<cstring>textLabel2</cstring>
</property>
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Threshold:</string>
</property>
</widget>
</grid>
</widget>
</vbox>
</widget>
@ -376,6 +446,9 @@
<property name="name">
<cstring>groupBox1</cstring>
</property>
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>5</hsizetype>
@ -451,7 +524,7 @@
<connection>
<sender>radioContrast</sender>
<signal>toggled(bool)</signal>
<receiver>kcfg_BWTreshold</receiver>
<receiver>kcfg_BWThreshold</receiver>
<slot>setEnabled(bool)</slot>
</connection>
<connection>
@ -472,6 +545,18 @@
<receiver>textLabel1_2</receiver>
<slot>setEnabled(bool)</slot>
</connection>
<connection>
<sender>radioContrast</sender>
<signal>toggled(bool)</signal>
<receiver>textLabel2_2</receiver>
<slot>setEnabled(bool)</slot>
</connection>
<connection>
<sender>radioContrast</sender>
<signal>toggled(bool)</signal>
<receiver>kcfg_BWContrast</receiver>
<slot>setEnabled(bool)</slot>
</connection>
</connections>
<includes>
<include location="global" impldecl="in implementation">kdialog.h</include>

View file

@ -38,7 +38,10 @@
<cstring>kcfg_UseCompositing</cstring>
</property>
<property name="text">
<string>Enable transparency and other effects (default)</string>
<string>Enable &amp;transparency and other effects (default)</string>
</property>
<property name="accel">
<string>Alt+T</string>
</property>
</widget>
<widget class="QCheckBox">
@ -70,7 +73,10 @@
<cstring>lowRadio</cstring>
</property>
<property name="text">
<string>Low</string>
<string>&amp;Low</string>
</property>
<property name="accel">
<string>Alt+L</string>
</property>
</widget>
<widget class="QRadioButton">
@ -78,7 +84,10 @@
<cstring>normalRadio</cstring>
</property>
<property name="text">
<string>Normal (default)</string>
<string>&amp;Normal (default)</string>
</property>
<property name="accel">
<string>Alt+N</string>
</property>
</widget>
<widget class="QRadioButton">
@ -86,7 +95,10 @@
<cstring>aggressiveRadio</cstring>
</property>
<property name="text">
<string>Aggressive</string>
<string>&amp;Aggressive</string>
</property>
<property name="accel">
<string>Alt+A</string>
</property>
</widget>
<widget class="QLabel">

View file

@ -25,15 +25,20 @@
</choices>
</entry>
<entry key="RecolorForeground" type="Color" >
<default code="true" >Qt::black</default>
<default code="true" >0x600000</default>
</entry>
<entry key="RecolorBackground" type="Color" >
<default code="true" >Qt::white</default>
<default code="true" >0xF0F0F0</default>
</entry>
<entry key="BWTreshold" type="UInt" >
<default>5</default>
<min>1</min>
<max>10</max>
<entry key="BWThreshold" type="UInt" >
<default>127</default>
<min>2</min>
<max>253</max>
</entry>
<entry key="BWContrast" type="UInt" >
<default>2</default>
<min>2</min>
<max>6</max>
</entry>
</group>
<group name="General" >

View file

@ -387,7 +387,7 @@ void Part::slotNewConfig()
if ( m_searchWidget->isShown() != showSearch )
m_searchWidget->setShown( showSearch );
// Main View
// Main View (pageView)
QScrollView::ScrollBarMode scrollBarMode = Settings::showScrollBars() ?
QScrollView::AlwaysOn : QScrollView::AlwaysOff;
if ( m_pageView->hScrollBarMode() != scrollBarMode )
@ -395,6 +395,8 @@ void Part::slotNewConfig()
m_pageView->setHScrollBarMode( scrollBarMode );
m_pageView->setVScrollBarMode( scrollBarMode );
}
// update Main View contents (this should be done only if renderMode changed)
m_pageView->updateContents();
}
void Part::slotPrintPreview()

View file

@ -228,7 +228,7 @@ void PageView::pageSetup( const QValueVector<KPDFPage*> & pageSet, bool document
PageViewMessage::Info, 4000 );
}
void PageView::pageSetCurrent( int pageNumber, const QRect & /*viewport*/ )
void PageView::pageSetCurrent( int pageNumber, const QRect & viewport )
{
// select next page
d->vectorIndex = 0;
@ -251,9 +251,11 @@ void PageView::pageSetCurrent( int pageNumber, const QRect & /*viewport*/ )
slotRelayoutPages();
// center the view to see the selected page
// FIXME take care of viewport
const QRect & r = d->activeItem->geometry();
center( r.left() + r.width() / 2, r.top() + visibleHeight() / 2 - 10 );
if ( viewport.isNull() || true ) // FIXME take care of viewport
{
const QRect & r = d->activeItem->geometry();
center( r.left() + r.width() / 2, r.top() + visibleHeight() / 2 - 10 );
}
slotRequestVisiblePixmaps();
// update zoom text if in a ZoomFit/* zoom mode
@ -638,11 +640,18 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e )
case 1:
d->document->slotBookmarkPage( kpdfPage->number(), !kpdfPage->isBookmarked() );
break;
case 2: // FiXME less hackish, please!
case 2:
// zoom: Fit Width, columns: 1. setActions + relayout + setPage + update
d->zoomMode = ZoomFitWidth;
Settings::setViewColumns( 1 );
d->aZoomFitWidth->setChecked( true );
updateZoom( ZoomFitWidth );
d->aZoomFitPage->setChecked( false );
d->aZoomFitText->setChecked( false );
d->aViewTwoPages->setChecked( false );
slotTwoPagesToggled( false );
viewport()->setUpdatesEnabled( false );
slotRelayoutPages();
viewport()->setUpdatesEnabled( true );
updateContents();
d->document->slotSetCurrentPage( kpdfPage->number() );
break;
case 3: // ToDO switch to edit mode
@ -838,61 +847,108 @@ void PageView::paintItems( QPainter * p, const QRect & contentsRect )
for ( ; iIt != iEnd; ++iIt )
{
// check if a piece of the page intersects the contents rect
if ( (*iIt)->geometry().intersects( checkRect ) )
if ( !(*iIt)->geometry().intersects( checkRect ) )
continue;
PageViewItem * item = *iIt;
QRect pixmapGeometry = item->geometry();
// translate the painter so we draw top-left pixmap corner in 0,0
p->save();
p->translate( pixmapGeometry.left(), pixmapGeometry.top() );
// item pixmap and outline geometry
QRect outlineGeometry = pixmapGeometry;
outlineGeometry.addCoords( -1, -1, 3, 3 );
// draw the page outline (little black border and 2px shadow)
if ( !pixmapGeometry.contains( contentsRect ) )
{
PageViewItem * item = *iIt;
QRect pixmapGeometry = item->geometry();
// translate the painter so we draw top-left pixmap corner in 0,0
p->save();
p->translate( pixmapGeometry.left(), pixmapGeometry.top() );
// item pixmap and outline geometry
QRect outlineGeometry = pixmapGeometry;
outlineGeometry.addCoords( -1, -1, 3, 3 );
if ( !pixmapGeometry.contains( contentsRect ) )
int pixmapWidth = pixmapGeometry.width(),
pixmapHeight = pixmapGeometry.height();
// draw simple outline
p->setPen( Qt::black );
p->drawRect( -1, -1, pixmapWidth + 2, pixmapHeight + 2 );
// draw bottom/right gradient
int levels = 2;
int r = Qt::gray.red() / (levels + 2),
g = Qt::gray.green() / (levels + 2),
b = Qt::gray.blue() / (levels + 2);
for ( int i = 0; i < levels; i++ )
{
int pixmapWidth = pixmapGeometry.width(),
pixmapHeight = pixmapGeometry.height();
// draw simple outline
p->setPen( Qt::black );
p->drawRect( -1, -1, pixmapWidth + 2, pixmapHeight + 2 );
// draw bottom/right gradient
int levels = 2;
int r = Qt::gray.red() / (levels + 2),
g = Qt::gray.green() / (levels + 2),
b = Qt::gray.blue() / (levels + 2);
for ( int i = 0; i < levels; i++ )
{
p->setPen( QColor( r * (i+2), g * (i+2), b * (i+2) ) );
p->drawLine( i, i + pixmapHeight + 1, i + pixmapWidth + 1, i + pixmapHeight + 1 );
p->drawLine( i + pixmapWidth + 1, i, i + pixmapWidth + 1, i + pixmapHeight );
p->setPen( Qt::gray );
p->drawLine( -1, i + pixmapHeight + 1, i - 1, i + pixmapHeight + 1 );
p->drawLine( i + pixmapWidth + 1, -1, i + pixmapWidth + 1, i - 1 );
}
p->setPen( QColor( r * (i+2), g * (i+2), b * (i+2) ) );
p->drawLine( i, i + pixmapHeight + 1, i + pixmapWidth + 1, i + pixmapHeight + 1 );
p->drawLine( i + pixmapWidth + 1, i, i + pixmapWidth + 1, i + pixmapHeight );
p->setPen( Qt::gray );
p->drawLine( -1, i + pixmapHeight + 1, i - 1, i + pixmapHeight + 1 );
p->drawLine( i + pixmapWidth + 1, -1, i + pixmapWidth + 1, i - 1 );
}
// draw the pixmap (note: this modifies the painter)
if ( contentsRect.intersects( pixmapGeometry ) )
{
QRect pixmapRect = contentsRect.intersect( pixmapGeometry );
pixmapRect.moveBy( -pixmapGeometry.left(), -pixmapGeometry.top() );
// accessibility setting (TODO ADD COMPOSITING for PAGE RECOLORING)
if ( Settings::renderMode() == Settings::EnumRenderMode::Inverted )
p->setRasterOp( Qt::NotCopyROP );
// draw the pixmap
item->page()->drawPixmap( PAGEVIEW_ID, p, pixmapRect, pixmapGeometry.width(), pixmapGeometry.height() );
}
// remove painted area from 'remainingArea'
remainingArea -= outlineGeometry.intersect( contentsRect );
p->restore();
}
// draw the pixmap (note: this modifies the painter (not saved for performance))
if ( contentsRect.intersects( pixmapGeometry ) )
{
QRect pixmapRect = contentsRect.intersect( pixmapGeometry );
pixmapRect.moveBy( -pixmapGeometry.left(), -pixmapGeometry.top() );
// handle pixmap drawing in respect of accessibility settings
if ( Settings::renderMode() != Settings::EnumRenderMode::Normal )
{
// paint pixmapRect area in internal pixmap
QPixmap pagePix( pixmapRect.width(), pixmapRect.height() );
QPainter pixmapPainter( &pagePix );
pixmapPainter.translate( -pixmapRect.left(), -pixmapRect.top() );
item->page()->drawPixmap( PAGEVIEW_ID, &pixmapPainter, pixmapRect, pixmapGeometry.width(), pixmapGeometry.height() );
pixmapPainter.end();
// perform 'accessbility' enhancements on the (already painted) pixmap
QImage pageImage = pagePix.convertToImage();
switch ( Settings::renderMode() )
{
case Settings::EnumRenderMode::Inverted:
// Invert image pixels using QImage internal function
pageImage.invertPixels(false);
break;
case Settings::EnumRenderMode::Recolor:
// Recolor image using KImageEffect::flatten with dither:0
KImageEffect::flatten( pageImage, Settings::recolorForeground(), Settings::recolorBackground() );
break;
case Settings::EnumRenderMode::BlackWhite:
// Manual Gray and Contrast
unsigned int * data = (unsigned int *)pageImage.bits();
int val, pixels = pageImage.width() * pageImage.height(),
con = Settings::bWContrast(), thr = 255 - Settings::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;
}
pagePix.convertFromImage( pageImage );
// copy internal pixmap to the page
p->drawPixmap( pixmapRect.left(), pixmapRect.top(), pagePix );
}
else // paint pixmapRect area (as it is) in external painter
item->page()->drawPixmap( PAGEVIEW_ID, p, pixmapRect, pixmapGeometry.width(), pixmapGeometry.height() );
}
// remove painted area from 'remainingArea' and restore painter
remainingArea -= outlineGeometry.intersect( contentsRect );
p->restore();
}
// paint with background color the unpainted area