[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-kimageshop
Subject: stuckness :-(
From: Boudewijn Rempt <boud () valdyas ! org>
Date: 2007-09-27 20:56:23
Message-ID: 200709272256.25863.boud () valdyas ! org
[Download RAW message or body]
[Attachment #2 (multipart/signed)]
[Attachment #4 (multipart/mixed)]
I've been busy before I lost my last laptop and after I got my new one working
on the qpainter canvas. This canvas is pretty essential, since it's the
default and there's a lot of variation in what different systems support.
I've made it extremely configurable:
* it can either get the image pixels from KisImage using nearest neighbour, or
cache the KisImage projection as a QImage (with a size limit)
* it can smootscale using blitz or qt for scale < 1.0
* it can optionally smooth using Casper's fixed routine between 1.0 and 2.0
* it can create a qpixmap or a qimage (at least, htere's api for that, but no
implementation yet)
* and there are more settings and options to make sure it works on 32 and 64
bit systems, xrender and no xrender
But I'm stuck; even with the "normal" path (caching, blitz < 1.0, sample
1.0-2.0, qpainter scaling > 2.0), I get artefacts and the canvas thinks the
image is bigger than it really is.
I don't want to commit, since it breaks Krita horribly, but I would appreciate
any help! So here's the patch, if the mailing list lets it through...
--
Boudewijn Rempt
http://www.valdyas.org/fading/index.cgi
["projection.diff" (text/x-diff)]
Index: kis_prescaled_projection.cpp
===================================================================
--- kis_prescaled_projection.cpp (revision 717978)
+++ kis_prescaled_projection.cpp (working copy)
@@ -25,6 +25,7 @@
#include <QPoint>
#include <QSize>
#include <QPainter>
+#include <QTimer>
#include <qimageblitz.h>
@@ -95,10 +96,10 @@
/*
Sample each row.
*/
- j=(-1);
- for (y=0; y < (long) sample_image.height(); y++)
+ j = (-1);
+ for (y = 0; y < (long) sample_image.height(); y++)
{
- q= sample_image.scanLine( y );
+ q = sample_image.scanLine( y );
if (j != y_offset[y] )
{
/*
@@ -111,9 +112,9 @@
/*
Sample each column.
*/
- for (x=0; x < (long) sample_image.width(); x++)
+ for (x = 0; x < (long) sample_image.width(); x++)
{
- *(QRgb*)q=((QRgb*)pixels)[ x_offset[x] ];
+ *(QRgb*)q = ((QRgb*)pixels)[ x_offset[x] ];
q += 4;
}
}
@@ -124,8 +125,6 @@
return sample_image;
}
-
-
struct KisPrescaledProjection::Private
{
Private()
@@ -134,7 +133,7 @@
, useNearestNeighbour( false )
, useQtScaling( false )
, useSampling( false )
- , useSmoothScaling( true ) // Default
+ , smoothBetween100And200Percent( true )
, drawCheckers( false )
, scrollCheckers( false )
, drawMaskVisualisationOnUnscaledCanvasCache( false )
@@ -148,6 +147,7 @@
, monitorProfile( 0 )
, exposure( 0.0 )
{
+ smoothingTimer.setSingleShot( true );
}
bool updateAllOfQPainterCanvas;
bool useDeferredSmoothing; // first sample, then smoothscale when
@@ -158,26 +158,30 @@
// 1.0
bool useSampling; // use the above sample function instead
// qpainter's built-in scaling when zoom > 1.0
- bool useSmoothScaling; // Use blitz' smootscale when zoom < 1.0
+ bool smoothBetween100And200Percent; // if true, when zoom is
+ // between 1.0 and 2.0,
+ // smoothscale
bool drawCheckers;
bool scrollCheckers;
bool drawMaskVisualisationOnUnscaledCanvasCache;
bool cacheKisImageAsQImage;
bool showMask;
+
QColor checkersColor;
qint32 checkSize;
QImage unscaledCache;
QImage prescaledQImage;
QPixmap prescaledPixmap;
- QPoint documentOffset;
- QSize canvasSize;
- QSize imageSize;
+ QPoint documentOffset; // in view pixels
+ QSize canvasSize; // in view pixels
+ QSize imageSize; // in kisimage pixels
KisImageSP image;
KoViewConverter * viewConverter;
- KoColorProfile * monitorProfile;
+ const KoColorProfile * monitorProfile;
float exposure;
KisNodeSP currentNode;
- QTimer t;
+ QTimer smoothingTimer;
+ QRegion rectsToSmooth;
};
KisPrescaledProjection::KisPrescaledProjection()
@@ -185,7 +189,7 @@
, m_d( new Private() )
{
updateSettings();
- connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), \
SLOT(updateSettings())); + connect( &m_d->smoothingTimer, SIGNAL( timeout() ), \
this, SLOT( slotDoSmoothScale() ) ); }
KisPrescaledProjection::~KisPrescaledProjection()
@@ -196,9 +200,28 @@
void KisPrescaledProjection::setImage( KisImageSP image )
{
+ Q_ASSERT( image );
m_d->image = image;
+ setImageSize( image->width(), image->height() );
}
+void KisPrescaledProjection::setImageSize(qint32 w, qint32 h)
+{
+ kDebug() << "Setting image size from " << m_d->imageSize << " to " << w << ", " \
<< h; + // XXX: Make the limit of 50 megs configurable
+ if ( w * h * 4 > 50 * 1024 * 1024 ) {
+ m_d->prescaledQImage = QImage();
+ m_d->cacheKisImageAsQImage = false;
+ }
+
+ m_d->imageSize = QSize( w, h );
+ if ( !m_d->useNearestNeighbour && m_d->cacheKisImageAsQImage ) {
+ m_d->unscaledCache = QImage( w, h, QImage::Format_ARGB32 );
+ updateCanvasProjection( QRect( 0, 0, w, h ) );
+ }
+}
+
+
bool KisPrescaledProjection::drawCheckers() const
{
return m_d->drawCheckers;
@@ -230,78 +253,114 @@
KisConfig cfg;
m_d->updateAllOfQPainterCanvas = cfg.updateAllOfQPainterCanvas();
m_d->useDeferredSmoothing = cfg.useDeferredSmoothing();
- m_d->useNearestNeighbour = cfg.fastZoom();
+ m_d->useNearestNeighbour = cfg.useNearestNeigbour();
m_d->useQtScaling = cfg.useQtSmoothScaling();
m_d->useSampling = cfg.useSampling();
// If any of the above are true, we don't use our own smooth scaling
- m_d->useSmoothScaling = !( m_d->useNearestNeighbour ||
- m_d->useSampling ||
- m_d->useQtScaling ||
- m_d->useDeferredSmoothing );
m_d->scrollCheckers = cfg.scrollCheckers();
m_d->checkSize = cfg.checkSize();
m_d->checkersColor = cfg.checkersColor();
+
m_d->cacheKisImageAsQImage = cfg.cacheKisImageAsQImage();
+ if ( !m_d->cacheKisImageAsQImage ) m_d->unscaledCache = QImage();
+
m_d->drawMaskVisualisationOnUnscaledCanvasCache = \
cfg.drawMaskVisualisationOnUnscaledCanvasCache(); +
+ // XXX: Make config setting
+ m_d->smoothBetween100And200Percent = true;
+
+ kDebug(41010) << "QPainter canvas will render with the following options:\n"
+ << "\t updateAllOfQPainterCanvas: " << \
m_d->updateAllOfQPainterCanvas << "\n" + << "\t \
useDeferredSmoothing: " << m_d->useDeferredSmoothing << "\n" + << \
"\t useNearestNeighbour: " << m_d->useNearestNeighbour << "\n" + << \
"\t useQtScaling: " << m_d->useQtScaling << "\n" + << "\t \
useSampling: " << m_d->useSampling << "\n" + << "\t \
smoothBetween100And200Percent: " << m_d->smoothBetween100And200Percent; }
void KisPrescaledProjection::documentOffsetMoved( const QPoint &documentOffset )
{
+ qDebug() << "documentOffsetMoved " << m_d->documentOffset << ", to " << \
documentOffset; m_d->documentOffset = documentOffset;
-}
-void KisPrescaledProjection::updateCanvasProjection( const QRect & rc )
-{
+ // We've called documentOffsetMoved before even updating the projection
+ if ( m_d->prescaledQImage.isNull() ) {
- // We cache the KisImage as a QImage
- if ( !m_d->useNearestNeighbour ) {
+ return;
+ }
- if ( m_d->cacheKisImageAsQImage ) {
+ preScale();
+// Let someone else figure out the optimization where we copy the
+// still visible part of the image after moving the offset and then
+// only draw the newly visible parts
+#if 0
- QPainter p( &m_d->unscaledCache );
- p.setCompositionMode( QPainter::CompositionMode_Source );
+ qint32 width = m_d->prescaledQImage.width();
+ qint32 height = m_d->prescaledQImage.height();
- QImage updateImage = m_d->image->convertToQImage(rc.x(), rc.y(), \
rc.width(), rc.height(),
- m_d->monitorProfile,
- m_d->exposure);
+ QRegion exposedRegion = QRect(0, 0, width, height);
- if ( m_d->showMask && m_d->drawMaskVisualisationOnUnscaledCanvasCache ) \
{ + qint32 oldCanvasXOffset = m_d->documentOffset.x();
+ qint32 oldCanvasYOffset = m_d->documentOffset.y();
- // XXX: Also visualize the global selection
+ qDebug() << "w: " << width << ", h" << height << ", oldCanvasXOffset " << \
oldCanvasXOffset << ", oldCanvasYOffset " << oldCanvasYOffset + << ", new \
offset: " << documentOffset;
- KisSelectionSP selection = 0;
- if ( m_d->currentNode->inherits( "KisMask" ) ) {
- selection = dynamic_cast<const KisMask*>( \
m_d->currentNode.data() )->selection();
- }
- else if ( m_d->currentNode->inherits( "KisLayer" ) ) {
+ m_d->documentOffset = documentOffset;
- KisLayerSP layer = dynamic_cast<KisLayer*>( \
m_d->currentNode.data() );
- if ( KisSelectionMaskSP selectionMask = layer->selectionMask() ) \
{
- selection = selectionMask->selection();
- }
+ QImage img = QImage( width, height, QImage::Format_ARGB32 );
+ QPainter gc( &img );
+ gc.fillRect( 0, 0, width, height, QColor( 0, 0, 0, 0 ) );
+ gc.setCompositionMode( QPainter::CompositionMode_Source );
- // XXX: transitional! Remove when we use
- // KisSelectionMask instead of the selection in the
- // paintdevice. That way we can also select on groups etc.
- if ( !selection && m_d->currentNode->inherits( "KisPaintLayer" ) \
) {
- KisPaintDeviceSP dev = ( dynamic_cast<KisPaintLayer*>( \
m_d->currentNode.data() ) )->paintDevice();
- if ( dev ) {
- selection = dev->selection();
- }
- }
- }
+ if (oldCanvasXOffset != m_d->documentOffset.x() || oldCanvasYOffset != \
m_d->documentOffset.y()) {
- QTime t;
- t.start();
- selection->paint(&updateImage, rc);
- kDebug(41010) << "Mask visualisation rendering took: " << \
t.elapsed();
- }
+ qint32 deltaX = oldCanvasXOffset - m_d->documentOffset.x();
+ qint32 deltaY = oldCanvasYOffset - m_d->documentOffset.y();
- p.drawImage( rc.x(), rc.y(), updateImage, 0, 0, rc.width(), rc.height() \
);
- p.end();
+ qDebug() << "deltaX: " << deltaX << ", deltaY: " << deltaY;
+
+ gc.drawImage( deltaX, deltaY, m_d->prescaledQImage );
+ exposedRegion -= QRegion(QRect(0, 0, width - deltaX, height - deltaY));
+ }
+
+
+ if (!exposedRegion.isEmpty()) {
+
+ QVector<QRect> rects = exposedRegion.rects();
+
+ for (int i = 0; i < rects.count(); i++) {
+ QRect r = rects[i];
+ // Set the areas to empty. Who knows, there may be not
+ // enough image to draw in them.
+ gc.fillRect( r, QColor( 0, 0, 0, 0 ) );
+ qDebug() << "rect" << r;
+ // And conver the rect to document pixels, because that's
+ // what drawScaledImage expects.
+ drawScaledImage( imageRectFromViewPortPixels( r ), gc);
}
}
+ m_d->prescaledQImage = img;
+#endif
+}
+void KisPrescaledProjection::updateCanvasProjection( const QRect & rc )
+{
+ qDebug() << "updateCanvasProjection " << rc;
+ if ( !m_d->image ) {
+ kDebug() << "Calling updateCanvasProjection without an image: " << \
kBacktrace() << endl; + return;
+ }
+
+ // We cache the KisImage as a QImage
+ if ( !m_d->useNearestNeighbour ) {
+
+ if ( m_d->cacheKisImageAsQImage ) {
+
+ updateUnscaledCache( rc );
+ }
+ }
+
QRect vRect;
if ( m_d->updateAllOfQPainterCanvas ) {
@@ -317,15 +376,8 @@
}
-void KisPrescaledProjection::setImageSize(qint32 w, qint32 h)
-{
- m_d->imageSize = QSize( w, h );
- if ( !m_d->useNearestNeighbour || !m_d->cacheKisImageAsQImage ) {
- m_d->unscaledCache = QImage( w, h, QImage::Format_ARGB32 );
- }
-}
-void KisPrescaledProjection::setMonitorProfile( KoColorProfile * profile )
+void KisPrescaledProjection::setMonitorProfile( const KoColorProfile * profile )
{
m_d->monitorProfile = profile;
}
@@ -348,6 +400,7 @@
void KisPrescaledProjection::preScale()
{
+ Q_ASSERT( m_d->canvasSize.isValid() );
preScale( QRect( QPoint( 0, 0 ), m_d->canvasSize ) );
}
@@ -358,18 +411,31 @@
t.start();
QPainter gc( &m_d->prescaledQImage );
gc.setCompositionMode( QPainter::CompositionMode_Source );
+ gc.fillRect( rc, QColor( 0, 0, 0, 0 ) );
drawScaledImage( rc, gc);
kDebug(41010) <<"Prescaling took" << t.elapsed();
}
}
-void KisPrescaledProjection::resizePrescaledImage( QSize newSize, QSize oldSize )
+void KisPrescaledProjection::resizePrescaledImage( QSize newSize )
{
+
QTime t;
t.start();
+ QSize oldSize;
+
+ if ( m_d->prescaledQImage.isNull() ) {
+ oldSize = QSize( 0, 0 );
+ }
+ else {
+ oldSize = m_d->prescaledQImage.size();
+ }
+
+ qDebug() << "resizePrescaledImage from " << oldSize << " to " << newSize << \
endl; +
QImage img = QImage(newSize, QImage::Format_ARGB32);
QPainter gc( &img );
gc.setCompositionMode( QPainter::CompositionMode_Source );
@@ -382,7 +448,6 @@
QRegion r( QRect( 0, 0, newSize.width(), newSize.height() ) );
r -= QRegion( QRect( 0, 0, m_d->prescaledQImage.width(), \
m_d->prescaledQImage.height() ) );
-
foreach( QRect rc, r.rects() ) {
drawScaledImage( rc, gc );
}
@@ -391,6 +456,7 @@
gc.drawImage( 0, 0, m_d->prescaledQImage,
0, 0, m_d->prescaledQImage.width(), \
m_d->prescaledQImage.height() ); }
+
m_d->prescaledQImage = img;
m_d->canvasSize = newSize;
@@ -398,11 +464,13 @@
}
-void KisPrescaledProjection::drawScaledImage( const QRect & rc, QPainter & gc )
+void KisPrescaledProjection::drawScaledImage( const QRect & rc, QPainter & gc, bool \
isDeferredAction ) {
if ( !m_d->image )
return;
+ Q_ASSERT( m_d->viewConverter );
+
// get the x and y zoom level
double zoomX, zoomY;
m_d->viewConverter->zoom(&zoomX, &zoomY);
@@ -421,6 +489,8 @@
// compute how large a fully scaled image is in viewpixels
QSize dstSize = QSize(int(imagePixelSize.width() * scaleX ), int( \
imagePixelSize.height() * scaleY));
+ qDebug() << ">>>>>>>>>>>>>>>>>>>> dstSize: " << dstSize;
+
// Don't go outside the image (will crash the sampleImage method below)
QRect drawRect = rc.translated( m_d->documentOffset ).intersected(QRect( \
QPoint(0, 0), dstSize ) );
@@ -437,75 +507,103 @@
// the size of the rect after scaling
QSize scaledSize = QSize( ( int )( alignedImageRect.width() * scaleX ), ( int )( \
alignedImageRect.height() * scaleY ));
+ // Apparently we have never before tried to draw the image
+ if ( m_d->cacheKisImageAsQImage && m_d->unscaledCache.isNull() ) {
+ updateUnscaledCache( alignedImageRect );
+ }
// And now for deciding what to do and when -- the complicated bit
-
if ( scaleX > 1.0 - EPSILON && scaleY > 1.0 - EPSILON ) {
- kDebug(41010 ) << "Scale is 1.0, don't scale";
- QImage img;
- // Get the image directly from the KisImage
- if ( m_d->useNearestNeighbour || !m_d->cacheKisImageAsQImage ) {
- img = m_d->image->convertToQImage( drawRect, 1.0, 1.0, \
m_d->monitorProfile, m_d->exposure ); + // Between 1.0 and 2.0, a box filter \
often gives a much nicer + // result, according to pippin. The default blitz \
filter is + // called "blackman"
+ if ( m_d->smoothBetween100And200Percent && scaleX < 2.0 - EPSILON && scaleY \
< 2.0 - EPSILON ) { + QImage img;
+ if ( !m_d->cacheKisImageAsQImage ) {
+ img = m_d->image->convertToQImage( drawRect, scaleX, scaleY, \
m_d->monitorProfile, m_d->exposure ); + gc.drawImage( rc.topLeft(), \
img ); + }
+ else {
+ img = m_d->unscaledCache.copy( drawRect );
+ gc.save();
+ gc.scale(scaleX, scaleY);
+ gc.drawImage(rc.topLeft(), img);
+ gc.restore();
+ }
}
else {
- // Crop the canvascache
- img = m_d->unscaledCache.copy( drawRect );
- }
+ QImage img;
- // If so desired, use the sampleImage originally taken from
- // gwenview, which got it from mosfet, who got it from
- // ImageMagick
- if ( m_d->useSampling ) {
- gc.drawImage( rc.topLeft(), sampleImage(img, dstSize.width(), \
dstSize.height(), drawRect) ); + // Get the image directly from the \
KisImage + if ( m_d->useNearestNeighbour || !m_d->cacheKisImageAsQImage ) \
{ + img = m_d->image->convertToQImage( drawRect, 1.0, 1.0, \
m_d->monitorProfile, m_d->exposure ); + }
+ else {
+ // Crop the canvascache
+ img = m_d->unscaledCache.copy( drawRect );
+ }
+
+ // If so desired, use the sampleImage originally taken from
+ // gwenview, which got it from mosfet, who got it from
+ // ImageMagick
+ if ( m_d->useSampling ) {
+ gc.drawImage( rc.topLeft(), sampleImage(img, dstSize.width(), \
dstSize.height(), drawRect) ); + }
+ else {
+ // Else, let QPainter do the scaling, like we did in 1.6
+ gc.save();
+ gc.scale(scaleX, scaleY);
+ gc.drawImage(rc.topLeft(), img);
+ gc.restore();
+ }
}
- else {
- // Else, let QPainter do the scaling, like we did in 1.6
- gc.save();
- gc.scale(scaleX, scaleY);
- gc.drawImage(rc.topLeft(), img);
- gc.restore();
- }
}
else {
+ QImage croppedImage = m_d->unscaledCache.copy( alignedImageRect );
+
+ // Short circuit if we're in the deferred smoothing stage.
+ if ( isDeferredAction ) {
+ gc.drawImage( rc.topLeft(), Blitz::smoothScale( croppedImage, dstSize ) \
); + return;
+ }
+
// Use nearest neighbour interpolation from the raw KisImage
if ( m_d->useNearestNeighbour || m_d->useDeferredSmoothing ) {
if ( m_d->useDeferredSmoothing ) {
- // Start smoothing job. The job will be replaced by
- // the next smoothing job if it is added before this
- // one is done.
+ // XXX: Start smoothing job. The job will be replaced
+ // by the next smoothing job if it is added before
+ // this one is done.
+ m_d->rectsToSmooth += rc;
+ m_d->smoothingTimer.start(50);
}
QImage tmpImage = m_d->image->convertToQImage( alignedImageRect, scaleX, \
scaleY, m_d->monitorProfile, m_d->exposure ); gc.drawImage( rc.topLeft(), tmpImage \
); }
else {
-
-
- QImage croppedImage = m_d->unscaledCache.copy( alignedImageRect );
-
// If we don't cache the image as an unscaled QImage, get
// an unscaled QImage for this rect from KisImage.
if ( !m_d->cacheKisImageAsQImage ) {
-
+ croppedImage = m_d->image->convertToQImage( alignedImageRect.x(), \
alignedImageRect.y(), alignedImageRect.width(), alignedImageRect.height(), \
m_d->monitorProfile, m_d->exposure ); }
if ( m_d->useQtScaling ) {
+ gc.drawImage( rc.topLeft(), croppedImage.scaled( dstSize, \
Qt::KeepAspectRatio, Qt::SmoothTransformation ) ); }
else if ( m_d->useSampling ) {
-
+ gc.drawImage( rc.topLeft(), sampleImage(croppedImage, \
dstSize.width(), dstSize.height(), drawRect) ); }
else { // Smooth scaling using blitz
+ gc.drawImage( rc.topLeft(), Blitz::smoothScale( croppedImage, \
dstSize ) ); }
}
}
-
}
QRect KisPrescaledProjection::viewRectFromImagePixels( const QRect & rc )
{
- double xRes,yRes;
- xRes = m_d->image->xRes();
- yRes = m_d->image->yRes();
+ double xRes = m_d->image->xRes();
+ double yRes = m_d->image->yRes();
QRectF docRect;
docRect.setCoords((rc.left() - 2) / xRes, (rc.top() - 2) / yRes, (rc.right() + \
2) / xRes, (rc.bottom() + 2) / yRes); @@ -515,7 +613,80 @@
viewRect = viewRect.intersected( QRect( 0, 0, m_d->canvasSize.width(), \
m_d->canvasSize.width() ) );
return viewRect;
+}
+QRect KisPrescaledProjection::imageRectFromViewPortPixels( const QRect & \
viewportRect ) +{
+ QRect intersectedRect = viewportRect.intersected( QRect( 0, 0, \
m_d->canvasSize.width(), m_d->canvasSize.width() ) ); + QRect translatedRect = \
intersectedRect.translated( -m_d->documentOffset ); + QRectF docRect = \
m_d->viewConverter->viewToDocument( translatedRect ); +
+ return m_d->image->documentToIntPixel( docRect ).intersected( \
m_d->image->bounds() ); }
+void KisPrescaledProjection::slotDoSmoothScale()
+{
+ QRect rc = m_d->rectsToSmooth.boundingRect();
+ QPainter gc( &m_d->prescaledQImage );
+ gc.setCompositionMode( QPainter::CompositionMode_Source );
+ drawScaledImage( rc, gc, true);
+ m_d->rectsToSmooth = QRegion();
+ emit sigPrescaledProjectionUpdated( rc );
+}
+
+void KisPrescaledProjection::updateUnscaledCache( const QRect & rc )
+{
+ qDebug() << rc;
+ if ( m_d->unscaledCache.isNull() ) {
+ m_d->unscaledCache = QImage( m_d->image->width(), m_d->image->height(), \
QImage::Format_ARGB32 ); + }
+
+ QPainter p( &m_d->unscaledCache );
+ p.setCompositionMode( QPainter::CompositionMode_Source );
+
+ QImage updateImage = m_d->image->convertToQImage(rc.x(), rc.y(), rc.width(), \
rc.height(), + \
m_d->monitorProfile, + \
m_d->exposure); +
+ if ( m_d->showMask && m_d->drawMaskVisualisationOnUnscaledCanvasCache ) {
+
+ // XXX: Also visualize the global selection
+
+ KisSelectionSP selection = 0;
+
+ if ( m_d->currentNode ) {
+ if ( m_d->currentNode->inherits( "KisMask" ) ) {
+
+ selection = dynamic_cast<const KisMask*>( m_d->currentNode.data() \
)->selection(); + }
+ else if ( m_d->currentNode->inherits( "KisLayer" ) ) {
+
+ KisLayerSP layer = dynamic_cast<KisLayer*>( m_d->currentNode.data() \
); + if ( KisSelectionMaskSP selectionMask = layer->selectionMask() ) \
{ + selection = selectionMask->selection();
+ }
+
+ // XXX: transitional! Remove when we use
+ // KisSelectionMask instead of the selection in
+ // the paintdevice. That way we can also select on
+ // groups etc.
+ if ( !selection && m_d->currentNode->inherits( "KisPaintLayer" ) ) {
+ KisPaintDeviceSP dev = ( dynamic_cast<KisPaintLayer*>( \
m_d->currentNode.data() ) )->paintDevice(); + if ( dev ) {
+ selection = dev->selection();
+ }
+ }
+ }
+ }
+ QTime t;
+ t.start();
+ selection->paint(&updateImage, rc);
+ kDebug(41010) << "Mask visualisation rendering took: " << t.elapsed();
+ }
+
+ p.drawImage( rc.x(), rc.y(), updateImage, 0, 0, rc.width(), rc.height() );
+ p.end();
+
+}
+
#include "kis_prescaled_projection.moc"
Index: kis_qpainter_canvas.h
===================================================================
--- kis_qpainter_canvas.h (revision 717978)
+++ kis_qpainter_canvas.h (working copy)
@@ -21,6 +21,7 @@
#include <QWidget>
#include "kis_abstract_canvas_widget.h"
+#include "kis_prescaled_projection.h"
class QImage;
class QPaintEvent;
@@ -47,7 +48,7 @@
virtual ~KisQPainterCanvas();
-
+ void setPrescaledProjection( KisPrescaledProjectionSP prescaledProjection );
public: // QWidget
/// reimplemented method from superclass
@@ -97,22 +98,8 @@
void documentOffsetMoved( QPoint );
- void preScale();
-
- void preScale( const QRect & rc );
-
private:
- /**
- * draw a scaled QImage of the projection onto the gc
- *
- * @param rc The desired rect in pixels
- * @param gc The painter we draw on
- */
- void drawScaledImage( const QRect & rc, QPainter &gc);
-
-private:
-
class Private;
Private * const m_d;
};
Index: kis_canvas2.h
===================================================================
--- kis_canvas2.h (revision 717978)
+++ kis_canvas2.h (working copy)
@@ -95,8 +95,6 @@
QWidget* canvasWidget();
- QImage canvasCache();
-
virtual KoUnit unit() const;
virtual KoToolProxy* toolProxy() const;
@@ -125,7 +123,6 @@
KisView2* view();
bool usingHDRExposureProgram();
- bool useFastZooming();
public slots:
@@ -153,9 +150,13 @@
*/
void slotConfigChanged();
+ /**
+ * Called whenever the display monitor profile resource changes
+ */
+ void slotSetDisplayProfile( KoColorProfile * profile );
+
private:
- void resetMonitorProfile();
void resetCanvas();
KisCanvas2(const KisCanvas2&);
@@ -170,7 +171,6 @@
* the widget.
*/
QRect viewRectFromDoc( const QRectF & docRect );
- QRect viewRectFromImagePixels( const QRect & imageRect );
private:
Index: kis_canvas2.cpp
===================================================================
--- kis_canvas2.cpp (revision 717978)
+++ kis_canvas2.cpp (working copy)
@@ -36,6 +36,7 @@
#include "KoToolProxy.h"
#include "KoSelection.h"
+#include "kis_prescaled_projection.h"
#include "kis_image.h"
#include "kis_doc2.h"
#include "kis_shape_layer.h"
@@ -69,7 +70,6 @@
, currentCanvasIsOpenGL( false )
, currentCanvasUsesOpenGLShaders( false )
, toolProxy( new KoToolProxy(parent) )
- , fastZooming( false )
{
}
@@ -88,38 +88,22 @@
bool currentCanvasIsOpenGL;
bool currentCanvasUsesOpenGLShaders;
KoToolProxy * toolProxy;
- QImage canvasCache; // XXX: use KisQPainterImageContext to share
- // cache data between views. Finish that
- // class. Or another way to tile the canvas
- // cache instead of having a QImage as big as
- // the image in pixels.
QPoint documentOffset;
KoShapeControllerBase * sc;
- bool fastZooming;
-
#ifdef HAVE_OPENGL
KisOpenGLImageTexturesSP openGLImageTextures;
#endif
bool updateAllOfQPainterCanvas;
+ KisPrescaledProjectionSP prescaledProjection;
};
KisCanvas2::KisCanvas2(KoViewConverter * viewConverter, KisView2 * view, \
KoShapeControllerBase * sc) : KoCanvasBase(sc)
, m_d ( new KisCanvas2Private(this, viewConverter, view) )
{
- KisConfig cfg;
-
- m_d->updateAllOfQPainterCanvas = cfg.updateAllOfQPainterCanvas();
- m_d->fastZooming = cfg.fastZoom();
- if ( m_d->canvasWidget && m_d->canvasWidget->widget() )
- m_d->canvasWidget->widget()->update();
-
- resetMonitorProfile();
createCanvas();
- connect( view->canvasController(), SIGNAL( moveDocumentOffset( const QPoint& ) \
),
- this, SLOT( documentOffsetMoved( const QPoint& ) ) );
- connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), \
SLOT(slotConfigChanged()));
-
+ connect( view->canvasController(), SIGNAL( moveDocumentOffset( const QPoint& ) \
), SLOT( documentOffsetMoved( const QPoint& ) ) ); + connect( \
KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged())); \
}
KisCanvas2::~KisCanvas2()
@@ -127,52 +111,6 @@
delete m_d;
}
-void KisCanvas2::createQPainterCanvas()
-{
-#ifdef HAVE_OPENGL
- m_d->openGLImageTextures = 0;
-#endif
- setCanvasWidget( new KisQPainterCanvas( this, m_d->view ) );
- m_d->currentCanvasIsOpenGL = false;
- KisConfig cfg;
- m_d->updateAllOfQPainterCanvas = cfg.updateAllOfQPainterCanvas();
-}
-
-void KisCanvas2::createOpenGLCanvas()
-{
-#ifdef HAVE_OPENGL
- if ( QGLFormat::hasOpenGL() ) {
- // XXX: The image isn't done loading here!
- m_d->openGLImageTextures = \
KisOpenGLImageTextures::getImageTextures(m_d->view->image(), \
m_d->monitorProfile);
- setCanvasWidget( new KisOpenGLCanvas2( this, m_d->view, \
m_d->openGLImageTextures ) );
- m_d->currentCanvasIsOpenGL = true;
- m_d->currentCanvasUsesOpenGLShaders = \
m_d->openGLImageTextures->usingHDRExposureProgram();
- }
- else {
- kWarning() << "Tried to create OpenGL widget when system doesn't have \
OpenGL\n";
- createQPainterCanvas();
- }
-#endif
-}
-
-void KisCanvas2::createCanvas()
-{
- KisConfig cfg;
- if ( cfg.useOpenGL() ) {
-#ifdef HAVE_OPENGL
- createOpenGLCanvas();
-#else
- kWarning() << "OpenGL requested while its not available, starting qpainter \
canvas";
- createQPainterCanvas();
-#endif
- }
- else {
- createQPainterCanvas();
-
- }
-
-}
-
void KisCanvas2::setCanvasWidget(QWidget * widget)
{
KisAbstractCanvasWidget * tmp = dynamic_cast<KisAbstractCanvasWidget*>( widget \
); @@ -189,11 +127,6 @@
}
}
-KisView2* KisCanvas2::view()
-{
- return m_d->view;
-}
-
void KisCanvas2::gridSize(double *horizontal, double *vertical) const
{
Q_ASSERT(horizontal);
@@ -231,32 +164,6 @@
return m_d->shapeManager;
}
-QRect KisCanvas2::viewRectFromDoc( const QRectF & rc )
-{
- QRect viewRect = m_d->viewConverter->documentToView(rc).toAlignedRect();
- viewRect = viewRect.translated( -m_d->documentOffset );
- viewRect = viewRect.intersected( QRect( 0, 0, \
m_d->canvasWidget->widget()->width(), \
m_d->canvasWidget->widget()->height() ) );
- return viewRect;
-}
-
-
-QRect KisCanvas2::viewRectFromImagePixels( const QRect & rc )
-{
- double pppx,pppy;
- pppx = image()->xRes();
- pppy = image()->yRes();
-
- QRectF docRect;
- docRect.setCoords((rc.left() - 2) / pppx, (rc.top() - 2) / pppy, (rc.right() + \
2) / pppx, (rc.bottom() + 2) / pppy);
-
- QRect viewRect = m_d->viewConverter->documentToView(docRect).toAlignedRect();
- viewRect = viewRect.translated( -m_d->documentOffset );
- viewRect = viewRect.intersected( QRect( 0, 0, \
m_d->canvasWidget->widget()->width(), \
m_d->canvasWidget->widget()->height() ) );
-
- return viewRect;
-
-}
-
void KisCanvas2::updateCanvas(const QRectF& rc)
{
// updateCanvas is called from tools, never from the projection
@@ -274,90 +181,141 @@
}
}
-void KisCanvas2::updateCanvasProjection( const QRect & rc )
+void KisCanvas2::updateInputMethodInfo() {
+ // TODO call (the protected) QWidget::updateMicroFocus() on the proper canvas \
widget... +}
+
+const KoViewConverter* KisCanvas2::viewConverter() const
{
-#ifdef HAVE_OPENGL
- // Should never have an OpenGL image context and get here as that
- // connects to the image directly.
- Q_ASSERT( m_d->openGLImageTextures.isNull() );
-#endif
- // XXX: Use the KisQPainterImageContext here
+ return m_d->viewConverter;
+}
- // When using fast zoom, we don't have a canvas cache
- if ( !m_d->fastZooming ) {
- QPainter p( &m_d->canvasCache );
- p.setCompositionMode( QPainter::CompositionMode_Source );
+QWidget* KisCanvas2::canvasWidget()
+{
+ return m_d->canvasWidget->widget();
+}
- QImage updateImage = image()->convertToQImage(rc.x(), rc.y(), rc.width(), \
rc.height(),
- m_d->monitorProfile,
- \
m_d->view->resourceProvider()->HDRExposure());
- KisLayerSP layer = resourceProvider()->resource( \
KisResourceProvider::CurrentKritaLayer ).value<KisLayerSP>();
- if (!layer) return;
+KoUnit KisCanvas2::unit() const
+{
+ return KoUnit(KoUnit::Pixel);
+}
- KisPaintDeviceSP dev = layer->paintDevice();
- if (!dev) return;
+KoToolProxy * KisCanvas2::toolProxy() const {
+ return m_d->toolProxy;
+}
- if (dev->hasSelection()){
- KisSelectionSP selection = dev->selection();
+void KisCanvas2::createQPainterCanvas()
+{
+#ifdef HAVE_OPENGL
+ m_d->openGLImageTextures = 0;
+#endif
+ m_d->currentCanvasIsOpenGL = false;
- QTime t;
- t.start();
- selection->paint(&updateImage, rc);
- kDebug(41010) << "Mask visualisation rendering took: " << t.elapsed();
+ KisQPainterCanvas * canvasWidget = new KisQPainterCanvas( this, m_d->view );
+ m_d->prescaledProjection = new KisPrescaledProjection();
+ m_d->prescaledProjection->setViewConverter( m_d->viewConverter );
- }
+ canvasWidget->setPrescaledProjection( m_d->prescaledProjection );
- p.drawImage( rc.x(), rc.y(), updateImage, 0, 0, rc.width(), rc.height() );
- p.end();
+ KisConfig cfg;
+ m_d->updateAllOfQPainterCanvas = cfg.updateAllOfQPainterCanvas();
+ connect( KisConfigNotifier::instance(), SIGNAL(configChanged()), \
m_d->prescaledProjection, SLOT(updateSettings())); + connect( \
m_d->view->resourceProvider(), SIGNAL( sigDisplayProfileChanged( const KoColorProfile \
* profile ) ), m_d->prescaledProjection, SLOT( setMonitorProfile( const \
KoColorProfile * ) ) ); +
+ setCanvasWidget( canvasWidget );
+}
+
+void KisCanvas2::createOpenGLCanvas()
+{
+#ifdef HAVE_OPENGL
+ if ( QGLFormat::hasOpenGL() ) {
+ // XXX: The image isn't done loading here!
+ m_d->openGLImageTextures = \
KisOpenGLImageTextures::getImageTextures(m_d->view->image(), m_d->monitorProfile); + \
setCanvasWidget( new KisOpenGLCanvas2( this, m_d->view, m_d->openGLImageTextures ) ); \
+ m_d->currentCanvasIsOpenGL = true; + \
m_d->currentCanvasUsesOpenGLShaders = \
m_d->openGLImageTextures->usingHDRExposureProgram(); }
else {
- // XXX: Draw the selection also if we're using fast scaling
- // instead of the canvas cache
+ kWarning() << "Tried to create OpenGL widget when system doesn't have \
OpenGL\n"; + createQPainterCanvas();
}
+#endif
+}
- QRect vRect = viewRectFromImagePixels( rc );
+void KisCanvas2::createCanvas()
+{
+ KisConfig cfg;
+ if ( cfg.useOpenGL() ) {
+#ifdef HAVE_OPENGL
+ createOpenGLCanvas();
+#else
+ kWarning() << "OpenGL requested while its not available, starting qpainter \
canvas"; + createQPainterCanvas();
+#endif
+ }
+ else {
+ createQPainterCanvas();
- if ( !vRect.isEmpty() ) {
-
- m_d->canvasWidget->preScale( vRect );
-
- if ( m_d->updateAllOfQPainterCanvas ) {
- m_d->canvasWidget->widget()->update();
- }
- else {
- m_d->canvasWidget->widget()->update( vRect );
- }
}
+
}
-
-void KisCanvas2::updateCanvas()
+KisView2* KisCanvas2::view()
{
- m_d->canvasWidget->widget()->update();
+ return m_d->view;
}
-const KoViewConverter* KisCanvas2::viewConverter() const
+QRect KisCanvas2::viewRectFromDoc( const QRectF & rc )
{
- return m_d->viewConverter;
+ QRect viewRect = m_d->viewConverter->documentToView(rc).toAlignedRect();
+ viewRect = viewRect.translated( -m_d->documentOffset );
+ viewRect = viewRect.intersected( QRect( 0, 0, \
m_d->canvasWidget->widget()->width(), m_d->canvasWidget->widget()->height() ) ); + \
return viewRect; }
-QWidget* KisCanvas2::canvasWidget()
+
+void KisCanvas2::updateCanvasProjection( const QRect & rc )
{
- return m_d->canvasWidget->widget();
+#ifdef HAVE_OPENGL
+ // Should never have an OpenGL image context and get here as that
+ // connects to the image directly.
+ Q_ASSERT( m_d->openGLImageTextures.isNull() );
+#endif
+ // XXX: Use the KisQPainterImageContext here
+
+ // If this does anything, it updates the pixel-for-pixel
+ // projection of the KisImage
+ m_d->prescaledProjection->updateCanvasProjection( rc );
+
+ QRect vRect = m_d->prescaledProjection->viewRectFromImagePixels( rc );
+
+ if ( !vRect.isEmpty() ) {
+
+ // If so desired, rescale all of the visible area so we don't
+ // see any jitter when using algorithms that cannot handle the
+ // +/- half pixel inaccuracy of our algorithms
+ if ( m_d->updateAllOfQPainterCanvas ) {
+ m_d->prescaledProjection->preScale();
+ }
+ else {
+ m_d->prescaledProjection->preScale( vRect );
+ }
+
+ // Regardless, the actual
+ m_d->canvasWidget->widget()->update( vRect );
+
+ }
}
-KoUnit KisCanvas2::unit() const
+void KisCanvas2::updateCanvas()
{
- return KoUnit(KoUnit::Pixel);
+ m_d->canvasWidget->widget()->update();
}
-KoToolProxy * KisCanvas2::toolProxy() const {
- return m_d->toolProxy;
-}
KisImageSP KisCanvas2::image()
{
@@ -365,32 +323,11 @@
}
-QImage KisCanvas2::canvasCache()
-{
- return m_d->canvasCache;
-}
-
KoColorProfile * KisCanvas2::monitorProfile()
{
- if (m_d->monitorProfile == 0) {
- resetMonitorProfile();
- }
return m_d->monitorProfile;
}
-
-void KisCanvas2::resetMonitorProfile()
-{
- // XXX: The X11 monitor profile overrides the settings
- m_d->monitorProfile = KoIccColorProfile::getScreenProfile();
-
- if (m_d->monitorProfile == 0) {
- KisConfig cfg;
- QString monitorProfileName = cfg.monitorProfile();
- m_d->monitorProfile = \
KoColorSpaceRegistry::instance()->profileByName(monitorProfileName);
- }
-}
-
KisImageSP KisCanvas2::currentImage()
{
return m_d->view->image();
@@ -398,10 +335,8 @@
void KisCanvas2::setImageSize( qint32 w, qint32 h )
{
- // Fast zoom takes the pixels directly from the QImage and doesn't
- // cache the image in a qimage
- if ( !m_d->fastZooming )
- m_d->canvasCache = QImage( w, h, QImage::Format_ARGB32 );
+ if ( m_d->prescaledProjection )
+ m_d->prescaledProjection->setImageSize( w, h );
}
void KisCanvas2::connectCurrentImage()
@@ -414,6 +349,11 @@
#endif
connect(m_d->view->image(), SIGNAL(sigImageUpdated(const QRect &)), \
SLOT(updateCanvasProjection(const QRect &)));
connect(m_d->view->image(), SIGNAL(sigSizeChanged(qint32, qint32)), \
SLOT(setImageSize( qint32, qint32)) ); +
+ if ( m_d->prescaledProjection ) {
+ m_d->prescaledProjection->setImage( m_d->view->image() );
+ }
+
#ifdef HAVE_OPENGL
}
#endif
@@ -431,7 +371,6 @@
void KisCanvas2::resetCanvas()
{
- resetMonitorProfile();
KisConfig cfg;
#if HAVE_OPENGL
@@ -453,7 +392,6 @@
}
#endif
m_d->updateAllOfQPainterCanvas = cfg.updateAllOfQPainterCanvas();
- m_d->fastZooming = cfg.fastZoom();
m_d->canvasWidget->widget()->update();
}
@@ -465,7 +403,9 @@
void KisCanvas2::preScale()
{
- m_d->canvasWidget->preScale();
+ Q_ASSERT( m_d->prescaledProjection );
+
+ m_d->prescaledProjection->preScale();
}
bool KisCanvas2::usingHDRExposureProgram()
@@ -480,18 +420,14 @@
return false;
}
-bool KisCanvas2::useFastZooming()
-{
- return m_d->fastZooming;
-}
-
void KisCanvas2::slotConfigChanged()
{
resetCanvas();
}
-void KisCanvas2::updateInputMethodInfo() {
- // TODO call (the protected) QWidget::updateMicroFocus() on the proper canvas \
widget... +void KisCanvas2::slotSetDisplayProfile( KoColorProfile * profile )
+{
+ m_d->monitorProfile = profile;
}
#include "kis_canvas2.moc"
Index: kis_qpainter_canvas.cpp
===================================================================
--- kis_qpainter_canvas.cpp (revision 717978)
+++ kis_qpainter_canvas.cpp (working copy)
@@ -18,6 +18,8 @@
#include "kis_qpainter_canvas.h"
+#include "kis_canvas2.h"
+
#include <QPaintEvent>
#include <QRect>
#include <QPainter>
@@ -45,10 +47,9 @@
#include <kis_layer.h>
+#include "kis_prescaled_projection.h"
#include "kis_config.h"
-#include "kis_canvas2.h"
#include "kis_resource_provider.h"
-#include <qimageblitz.h>
#include "kis_doc2.h"
#include "kis_grid_drawer.h"
#include "kis_selection_manager.h"
@@ -71,11 +72,11 @@
{
}
+ KisPrescaledProjectionSP prescaledProjection;
KoToolProxy * toolProxy;
KisCanvas2 * canvas;
const KoViewConverter * viewConverter;
QBrush checkBrush;
- QImage prescaledImage;
QPoint documentOffset;
KisGridDrawer* gridDrawer;
double currentExposure;
@@ -106,7 +107,10 @@
delete m_d;
}
-#define EPSILON 1e-6
+void KisQPainterCanvas::setPrescaledProjection( KisPrescaledProjectionSP \
prescaledProjection ) +{
+ m_d->prescaledProjection = prescaledProjection;
+}
void KisQPainterCanvas::paintEvent( QPaintEvent * ev )
{
@@ -120,7 +124,7 @@
if (img->colorSpace()->hasHighDynamicRange() &&
(m_d->currentExposure != \
m_d->canvas->view()->resourceProvider()->HDRExposure())) {
- // XXX: If we had a dirty region we could just update areas as
+ // XXX: If we had a dirty region we could just recomposite areas as
// they become visible.
// YYY: As soon as we start using
// KisProjection::setRegionOfInterest(), only the visible
@@ -171,7 +175,7 @@
t.restart();
gc.setCompositionMode( QPainter::CompositionMode_SourceOver );
- gc.drawImage( ev->rect(), m_d->prescaledImage, ev->rect() );
+ gc.drawImage( ev->rect(), m_d->prescaledProjection->prescaledQImage(), \
ev->rect() ); kDebug(41010) <<"Drawing image:" << t.elapsed();
#ifdef DEBUG_REPAINT
@@ -275,192 +279,13 @@
void KisQPainterCanvas::documentOffsetMoved( QPoint pt )
{
- qint32 width = m_d->prescaledImage.width();
- qint32 height = m_d->prescaledImage.height();
-
- QRegion exposedRegion = QRect(0, 0, width, height);
-
- qint32 oldCanvasXOffset = m_d->documentOffset.x();
- qint32 oldCanvasYOffset = m_d->documentOffset.y();
-
- m_d->documentOffset = pt;
-
- QImage img = QImage( width, height, QImage::Format_ARGB32 );
- QPainter gc( &img );
- gc.setCompositionMode( QPainter::CompositionMode_Source );
-
- if (!m_d->prescaledImage.isNull()) {
-
- if (oldCanvasXOffset != m_d->documentOffset.x() || oldCanvasYOffset != \
m_d->documentOffset.y()) {
-
- qint32 deltaX = m_d->documentOffset.x() - oldCanvasXOffset;
- qint32 deltaY = m_d->documentOffset.y() - oldCanvasYOffset;
-
- gc.drawImage( -deltaX, -deltaY, m_d->prescaledImage );
- exposedRegion -= QRegion(QRect(-deltaX, -deltaY, width - deltaX, height \
- deltaY));
- }
- }
-
-
- if (!m_d->prescaledImage.isNull() && !exposedRegion.isEmpty()) {
-
- QVector<QRect> rects = exposedRegion.rects();
-
- for (int i = 0; i < rects.count(); i++) {
- QRect r = rects[i];
- drawScaledImage( r, gc);
- }
- }
- m_d->prescaledImage = img;
+ m_d->prescaledProjection->documentOffsetMoved( pt );
update();
}
-
-void KisQPainterCanvas::drawScaledImage( const QRect & r, QPainter &gc )
-{
- KisImageSP img = m_d->canvas->image();
- if (img == 0) return;
- QRect rc = r;
-
- double sx, sy;
- m_d->viewConverter->zoom(&sx, &sy);
-
- // Compute the scale factors
- double scaleX = sx / img->xRes();
- double scaleY = sy / img->yRes();
-
- QImage canvasImage = m_d->canvas->canvasCache();
-
- // compute how large a fully scaled image is
- QSize dstSize = QSize(int(canvasImage.width() * scaleX ), int( \
canvasImage.height() * scaleY));
-
- // Don't go outside the image (will crash the sampleImage method below)
- QRect drawRect = rc.translated( \
m_d->documentOffset).intersected(QRect(QPoint(),dstSize));
-
- // Go from the widget coordinates to points
- QRectF imageRect = m_d->viewConverter->viewToDocument( rc.translated( \
m_d->documentOffset ) );
-
- double pppx,pppy;
- pppx = img->xRes();
- pppy = img->yRes();
-
- // Go from points to pixels
- imageRect.setCoords(imageRect.left() * pppx, imageRect.top() * pppy,
- imageRect.right() * pppx, imageRect.bottom() * pppy);
-
- // Don't go outside the image and convert to whole pixels
- QRect alignedImageRect = imageRect.intersected( canvasImage.rect() \
).toAlignedRect();
-
- if ( m_d->canvas->useFastZooming() ) {
-
- // XXX: Check whether the right coordinates are used
-
- QTime t;
- t.start();
- QImage tmpImage = img->convertToQImage( alignedImageRect, scaleX, scaleY, \
m_d->canvas->monitorProfile(), m_d->currentExposure );
- kDebug(41010 ) << "KisImage::convertToQImage" << t.elapsed();
- gc.drawImage( rc.topLeft(), tmpImage );
-
- }
- else {
-
- // Don't scale if not necessary;
- if ( scaleX == 1.0 && scaleY == 1.0 ) {
- gc.drawImage( rc.topLeft(), canvasImage.copy( drawRect ) );
- }
- else {
- QSize sz = QSize( ( int )( alignedImageRect.width() * scaleX ), ( int )( \
alignedImageRect.height() * scaleY ));
- QImage croppedImage = canvasImage.copy( alignedImageRect );
-
- if ( sx >= 1.0 && sy >= 1.0 ) {
- QTime t;
- t.start();
- QImage img2 = croppedImage.scaled( sz, Qt::KeepAspectRatio, \
Qt::FastTransformation );
- kDebug(41010) << "QImage fast scaling " << t.elapsed();
- gc.drawImage( rc.topLeft(), img2 );
- }
- else {
-
-
- QTime t;
- t.start();
-#ifndef USE_QT_SCALING
- QImage img2 = Blitz::smoothScale( croppedImage, sz );
- kDebug(41010) <<"Blitz scale:" << t.elapsed();
-#else
- t.restart();
- QImage img2 = croppedImage.scaled( sz, Qt::KeepAspectRatio, \
Qt::SmoothTransformation );
- kDebug(41010) <<"qimage smooth scale:" << t.elapsed();
-#endif
- gc.drawImage( rc.topLeft(), img2 );
-
-
- //gc.drawImage( rc.topLeft(), ImageUtils::scale(croppedImage, \
sz.width(), sz.height() ));
-
- }
- }
-
- }
-}
-
void KisQPainterCanvas::resizeEvent( QResizeEvent *e )
{
- QTime t;
- t.start();
-
-
- QSize newSize = e->size();
- QSize oldSize = m_d->prescaledImage.size();
-
- QImage img = QImage(e->size(), QImage::Format_ARGB32);
- QPainter gc( &img );
- gc.setCompositionMode( QPainter::CompositionMode_Source );
- gc.drawImage( 0, 0, m_d->prescaledImage, 0, 0, m_d->prescaledImage.width(), \
m_d->prescaledImage.height() );
-
- if ( newSize.width() > oldSize.width() || newSize.height() > oldSize.height() ) \
{
-
- QRect right( oldSize.width(), 0, newSize.width() - oldSize.width(), \
newSize.height() );
- if ( right.width() > 0 ) {
- drawScaledImage( right, gc);
- }
- // Subtract the right hand overlap part (right.width() from
- // the bottom band so we don't scale the same area twice.
- QRect bottom( 0, oldSize.height(), newSize.width() - right.width(), \
newSize.height() - oldSize.height() );
- if ( bottom.height() > 0 ) {
- drawScaledImage( bottom, gc);
- }
-
- }
- m_d->prescaledImage = img;
-
- kDebug(41010) <<"Resize event:" << t.elapsed();
+ m_d->prescaledProjection->resizePrescaledImage( e->size() );
}
-void KisQPainterCanvas::preScale()
-{
- // Thread this!
- QTime t;
- t.start();
- m_d->prescaledImage = QImage( size(), QImage::Format_ARGB32);
-
- QPainter gc( &m_d->prescaledImage );
- gc.setCompositionMode( QPainter::CompositionMode_Source );
-
- drawScaledImage( QRect( QPoint( 0, 0 ), size() ), gc);
- kDebug(41010) <<"preScale():" << t.elapsed();
-
-}
-
-void KisQPainterCanvas::preScale( const QRect & rc )
-{
- if ( !rc.isEmpty() ) {
- QTime t;
- t.start();
- QPainter gc( &m_d->prescaledImage );
- gc.setCompositionMode( QPainter::CompositionMode_Source );
- drawScaledImage( rc, gc);
- kDebug(41010) <<"Prescaling took" << t.elapsed();
- }
-}
-
#include "kis_qpainter_canvas.moc"
Index: kis_zoom_manager.cc
===================================================================
--- kis_zoom_manager.cc (revision 717978)
+++ kis_zoom_manager.cc (working copy)
@@ -112,7 +112,9 @@
connect(m_canvasController, SIGNAL(canvasOffsetYChanged(int)),
m_verticalRuler, SLOT(setOffset(int)));
- connect( m_canvasController, SIGNAL( canvasMousePositionChanged(const QPoint & ) \
), this, SLOT( mousePositionChanged( const QPoint & ) ) ); + connect( \
m_canvasController, + SIGNAL( canvasMousePositionChanged(const QPoint & ) \
), + SLOT( mousePositionChanged( const QPoint & ) ) );
connect(m_zoomController, SIGNAL(zoomChanged(KoZoomMode::Mode, double)),
this, SLOT(slotZoomChanged(KoZoomMode::Mode, double)));
@@ -166,9 +168,10 @@
m_view->canvasBase()->preScale();
m_view->canvas()->update();
- m_canvasController->setDocumentSize(
- QSize( int(0.5 + m_zoomHandler->documentToViewX(img->width() / \
img->xRes())),
- int(0.5 + m_zoomHandler->documentToViewY(img->height() / \
img->yRes())) ) ); + QSize sz = QSize( int(0.5 + \
m_zoomHandler->documentToViewX(img->width() / img->xRes())), + \
int(0.5 + m_zoomHandler->documentToViewY(img->height() / img->yRes())) ); + \
qDebug() << "Resizing after change in aspect mode to to " << sz; + \
m_canvasController->setDocumentSize( sz );
// Finally ask the canvasController to recenter
m_canvasController->recenterPreferred();
Index: kis_abstract_canvas_widget.h
===================================================================
--- kis_abstract_canvas_widget.h (revision 717978)
+++ kis_abstract_canvas_widget.h (working copy)
@@ -52,20 +52,6 @@
KisCanvas2 * canvas, KisGridDrawer * gridDrawer );
/**
- * Prescale the canvas represention of the image (if necessary, it
- * is for QPainter, not for OpenGL).
- */
- virtual void preScale() {}
-
- /**
- * Prescale the canvas represetation of the image.
- *
- * @param rc The target rect in view coordinates of the prescaled
- * image, pre-translated with the document offset
- */
- virtual void preScale( const QRect & rc ) { Q_UNUSED( rc ); }
-
- /**
* Returns one check of the background checkerboard pattern.
*
* @param checkSize the size of the check
Index: tests/kis_prescaled_projection_test.cpp
===================================================================
--- tests/kis_prescaled_projection_test.cpp (revision 717978)
+++ tests/kis_prescaled_projection_test.cpp (working copy)
@@ -20,9 +20,134 @@
#include <QCoreApplication>
#include <qtest_kde.h>
+
+#include <QSize>
+#include <QImage>
+
+#include <KoZoomHandler.h>
+#include <KoColorSpaceRegistry.h>
+
+#include <kis_types.h>
+#include <kis_image.h>
+#include <kis_paint_layer.h>
+#include <kis_group_layer.h>
+
#include "kis_prescaled_projection_test.h"
#include "kis_prescaled_projection.h"
+
+bool KisPrescaledProjectionTest::testProjectionScenario( KisPrescaledProjection & \
projection, + KoZoomHandler * \
viewConverter, + const QString & \
name ) +{
+
+ qDebug() << 1;
+ projection.resizePrescaledImage( QSize( 1000, 1000 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_01.png" );
+
+ qDebug() << 21;
+ viewConverter->setZoom( 0.5 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_021.png" );
+
+ qDebug() << 22;
+ viewConverter->setZoom( 0.6 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_022.png" );
+
+ qDebug() << 23;
+ viewConverter->setZoom( 0.71 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_023.png" );
+
+ qDebug() << 24;
+ viewConverter->setZoom( 0.84 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_024.png" );
+
+ qDebug() << 25;
+ viewConverter->setZoom( 0.9 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_025.png" );
+
+ qDebug() << 3;
+ viewConverter->setZoom( 1.9 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_03.png" );
+
+ qDebug() << 4;
+ viewConverter->setZoom( 2.0 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_04.png" );
+
+ viewConverter->setZoom( 2.5 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_05.png" );
+
+ viewConverter->setZoom( 16.0 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_06.png" );
+
+ viewConverter->setZoom( 1.0 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_07.png" );
+
+ projection.documentOffsetMoved( QPoint( 50, 50 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_08.png" );
+
+ projection.documentOffsetMoved( QPoint( 100, 100 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_081.png" );
+
+ projection.documentOffsetMoved( QPoint( 200, 200 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_082.png" );
+
+ projection.documentOffsetMoved( QPoint( 250, 250 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_083.png" );
+
+ projection.documentOffsetMoved( QPoint( 150, 200 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_084.png" );
+
+ projection.documentOffsetMoved( QPoint( 100, 200 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_085.png" );
+
+ projection.documentOffsetMoved( QPoint( 50, 200 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_086.png" );
+
+ projection.documentOffsetMoved( QPoint( 0, 200 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_087.png" );
+
+ projection.resizePrescaledImage( QSize( 750, 750 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_09.png" );
+
+ viewConverter->setZoom( 1.0 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_10.png" );
+
+ projection.resizePrescaledImage( QSize( 350, 350 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_11.png" );
+
+ projection.documentOffsetMoved( QPoint( 100, 100 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_12.png" );
+
+ viewConverter->setZoom( 0.75 );
+ projection.preScale();
+ projection.prescaledQImage().save( name + "_prescaled_projection_13.png" );
+
+ projection.documentOffsetMoved( QPoint( 10, 10 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_14.png" );
+
+ projection.documentOffsetMoved( QPoint( 0, 0 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_15.png" );
+
+ projection.documentOffsetMoved( QPoint( 10, 10 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_16.png" );
+
+ projection.documentOffsetMoved( QPoint( 30, 50 ) );
+ projection.prescaledQImage().save( name + "_prescaled_projection_17.png" );
+
+
+}
+
void KisPrescaledProjectionTest::testCreation()
{
KisPrescaledProjection * prescaledProjection = 0;
@@ -34,6 +159,93 @@
delete prescaledProjection;
}
+
+void KisPrescaledProjectionTest::testCoordinateConversionRoundTrip()
+{
+ KisPrescaledProjection projection;
+
+ KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
+ KisImageSP image = new KisImage( 0, 100, 100, cs, "projection test" );
+ image->setResolution( 300, 300 );
+
+ KoZoomHandler * viewConverter = new KoZoomHandler();
+ viewConverter->setResolution(120, 120);
+
+ projection.setImage( image );
+ projection.setViewConverter( viewConverter );
+ projection.resizePrescaledImage( QSize( 100, 100 ) );
+
+ QRect viewRect = projection.viewRectFromImagePixels( QRect( 0, 0, 100, 100 ) );
+ QCOMPARE( viewRect, QRect( 0, 0, 41, 41 ) );
+
+ QRect viewRect2 = projection.viewRectFromImagePixels( QRect( 0, 0, 200, 200 ) );
+ QCOMPARE( viewRect2, QRect( 0, 0, 81, 81 ) );
+
+ QRect imageRect = projection.imageRectFromViewPortPixels( viewRect );
+ QCOMPARE( imageRect, QRect( 0, 0, 100, 100 ) );
+
+ QRect viewRect3 = projection.viewRectFromImagePixels( imageRect );
+ QCOMPARE( viewRect3, viewRect );
+}
+
+
+void KisPrescaledProjectionTest::testScalingUndeferredSmoothingPixelForPixel()
+{
+ // Set up a nice image
+ QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "lena.png");
+
+ // Undo adapter not necessary
+ KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
+ KisImageSP image = new KisImage( 0, qimage.width(), qimage.height(), cs, \
"projection test" ); +
+ // 300 dpi recalculated to pixels per point (of which there are 72
+ // to the inch)
+ image->setResolution( 100 / 72 , 100 / 72 );
+
+ KisPaintLayerSP layer = new KisPaintLayer( image, "test", OPACITY_OPAQUE, cs );
+ image->addNode(layer.data(), image->rootLayer(), 0);
+ layer->paintDevice()->convertFromQImage( qimage, "");
+
+ KisPrescaledProjection projection;
+ projection.setImage( image );
+
+ KoZoomHandler * viewConverter = new KoZoomHandler();
+ projection.setViewConverter( viewConverter );
+ // pixel-for-pixel, at 100% zoom
+ viewConverter->setResolution(image->xRes(), image->yRes());
+
+ testProjectionScenario( projection, viewConverter, "pixel_for_pixel" );
+
+}
+
+
+void KisPrescaledProjectionTest::testScalingUndeferredSmoothing()
+{
+ // Set up a nice image
+ QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "lena.png");
+
+ // Undo adapter not necessary
+ KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
+ KisImageSP image = new KisImage( 0, qimage.width(), qimage.height(), cs, \
"projection test" ); +
+ // 300 dpi recalculated to pixels per point (of which there are 72
+ // to the inch)
+ image->setResolution( 300 / 72 , 300 / 72 );
+
+ KisPaintLayerSP layer = new KisPaintLayer( image, "test", OPACITY_OPAQUE, cs );
+ image->addNode(layer.data(), image->rootLayer(), 0);
+ layer->paintDevice()->convertFromQImage( qimage, "");
+
+ KisPrescaledProjection projection;
+ projection.setImage( image );
+
+ KoZoomHandler * viewConverter = new KoZoomHandler();
+ projection.setViewConverter( viewConverter );
+
+ testProjectionScenario( projection, viewConverter, "120dpi" );
+
+}
+
QTEST_KDEMAIN(KisPrescaledProjectionTest, GUI)
#include "kis_prescaled_projection_test.moc"
Index: tests/kis_prescaled_projection_test.h
===================================================================
--- tests/kis_prescaled_projection_test.h (revision 717978)
+++ tests/kis_prescaled_projection_test.h (working copy)
@@ -21,13 +21,36 @@
#include <QtTest/QtTest>
+
+class KisPrescaledProjection;
+class KoZoomHandler;
+class QString;
+
class KisPrescaledProjectionTest : public QObject
{
Q_OBJECT
+private:
+
+ /**
+ * test the projection through a normal, but complicated scenario.
+ * The prefix is used to save the result qimages and compare them
+ * to the prepared correct images.
+ */
+ bool testProjectionScenario( KisPrescaledProjection & projection, KoZoomHandler \
* viewConverter, const QString & name ); +
private slots:
void testCreation();
+
+ void testCoordinateConversionRoundTrip();
+
+ // Doesn't fail yet, but at least writes out several versions
+ // of a scaled image. Make them compare with the results when
+ // we're done and have everything okay for regressions
+ void testScalingUndeferredSmoothingPixelForPixel();
+
+ void testScalingUndeferredSmoothing();
};
#endif
Index: tests/CMakeLists.txt
===================================================================
--- tests/CMakeLists.txt (revision 717978)
+++ tests/CMakeLists.txt (working copy)
@@ -1,6 +1,8 @@
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
include_directories( ${KOMAIN_INCLUDES} ${KOGUIUTILS_INCLUDES} )
+add_definitions(-DFILES_DATA_DIR="\\"${CMAKE_CURRENT_SOURCE_DIR}/data/\\"")
+
########### next target ###############
set(kis_node_model_test_SRCS kis_node_model_test.cpp )
@@ -36,19 +38,19 @@
########### next target ###############
-set(kis_files_test_SRCS kis_files_test.cpp )
+set(kis_prescaled_projection_test_SRCS kis_prescaled_projection_test.cpp )
-kde4_add_unit_test(kis_files_test TESTNAME krita-ui-kis_files_test \
${kis_files_test_SRCS}) +kde4_add_unit_test(KisPrescaledProjectionTest TESTNAME \
krita-ui-kis_prescaled_projection_test ${kis_prescaled_projection_test_SRCS})
-target_link_libraries(kis_files_test ${KDE4_KDEUI_LIBS} kritaui \
${QT_QTTEST_LIBRARY})
-add_definitions(-DFILES_DATA_DIR="\\"${CMAKE_CURRENT_SOURCE_DIR}/data/\\"")
+target_link_libraries(KisPrescaledProjectionTest ${KDE4_KDEUI_LIBS} kritaui \
${QT_QTTEST_LIBRARY})
########### end ###############
+set(kis_files_test_SRCS kis_files_test.cpp )
-set(kis_prescaled_projection_test_SRCS kis_prescaled_projection_test.cpp )
+kde4_add_unit_test(kis_files_test TESTNAME krita-ui-kis_files_test \
${kis_files_test_SRCS})
-kde4_add_unit_test(KisPrescaledProjectionTest TESTNAME \
krita-ui-kis_prescaled_projection_test ${kis_prescaled_projection_test_SRCS}) \
+target_link_libraries(kis_files_test ${KDE4_KDEUI_LIBS} kritaui \
${QT_QTTEST_LIBRARY})
-target_link_libraries(KisPrescaledProjectionTest ${KDE4_KDEUI_LIBS} kritaui \
${QT_QTTEST_LIBRARY})
########### end ###############
+
Index: kis_view2.cpp
===================================================================
--- kis_view2.cpp (revision 717978)
+++ kis_view2.cpp (working copy)
@@ -181,7 +181,12 @@
m_d->canvas = new KisCanvas2( m_d->viewConverter, this, doc->shapeController() \
); m_d->canvasController->setCanvas( m_d->canvas );
+
m_d->resourceProvider = new KisResourceProvider( this );
+ m_d->resourceProvider->setCanvasResourceProvider( \
m_d->canvas->resourceProvider() ); +
+ connect( m_d->resourceProvider, SIGNAL( sigDisplayProfileChanged( const \
KoColorProfile * ) ), m_d->canvas, SLOT(slotSetDisplayProfile( const KoColorProfile * \
) ) ); +
createManagers();
createActions();
@@ -371,8 +376,6 @@
disconnect(m_d->doc, SIGNAL(sigLoadingFinished()), this, \
SLOT(slotLoadingFinished()));
KisImageSP img = image();
-
- m_d->canvas->setImageSize( img->width(), img->height() );
slotSetImageSize( img->width(), img->height() );
if(m_d->statusBar) {
@@ -648,8 +651,8 @@
{
if ( PreferencesDialog::editPreferences() ) {
KisConfigNotifier::instance()->notifyConfigChanged();
+ m_d->resourceProvider->resetDisplayProfile();
-
// Update the settings for all nodes -- they don't query
// KisConfig directly because they need the settings during
// compositing, and they don't connect to the confignotifier
Index: kis_prescaled_projection.h
===================================================================
--- kis_prescaled_projection.h (revision 717978)
+++ kis_prescaled_projection.h (working copy)
@@ -21,6 +21,7 @@
#include <QObject>
#include <krita_export.h>
+#include <kis_shared.h>
class QPixmap;
class QImage;
@@ -34,6 +35,9 @@
#include <kis_types.h>
+class KisPrescaledProjection;
+typedef KisSharedPtr<KisPrescaledProjection> KisPrescaledProjectionSP;
+
/**
* KisPrescaledProjection is responsible for keeping around a
* prescaled QImage representation that is always suitable for
@@ -62,7 +66,7 @@
* should become either a QImage the size of the nearest pyramid level
* or a tiled QImage representation like the OpenGL image textures.
*/
-class KRITAUI_EXPORT KisPrescaledProjection : QObject
+class KRITAUI_EXPORT KisPrescaledProjection : public QObject, public KisShared
{
Q_OBJECT
@@ -91,14 +95,16 @@
/**
* The pre-scaled pixmap includes the underlying checker
* represenation. It is only generated when the drawCheckers() is
- * true, otherwise it is empty.
+ * true, otherwise it is empty. The prescaled pixmal is exactly as
+ * big as the canvas widget in pixels.
*/
QPixmap prescaledPixmap() const;
/**
* Return the prescaled QImage. This image has a transparency
* channel and is therefore suitable for generated a prescaled
- * representation of an image for the KritaShape.
+ * representation of an image for the KritaShape. The prescaled
+ * image is exactly as big as the canvas widget in pixels.
*/
QImage prescaledQImage() const;
@@ -109,6 +115,13 @@
*/
void setViewConverter( KoViewConverter * viewConverter );
+ /**
+ * Return the intersection of the widget size and the given rect
+ * in image pixels converted to widget pixels.
+ */
+ QRect viewRectFromImagePixels( const QRect & imageRect );
+
+
public slots:
/**
@@ -127,6 +140,8 @@
/**
* The image projection has changed, now update the canvas
* representation of it.
+ *
+ * @param rc the are to be updated in image pixels
*/
void updateCanvasProjection( const QRect & rc );
@@ -144,19 +159,20 @@
/**
* preScale and draw onto the scaled projection the specfied rect,
- * in KisImage pixels.
+ * in canvas view pixels.
*/
void preScale( const QRect & rc );
/**
- * Resize the prescaled image.
+ * Resize the prescaled image. The size is given in canvas
+ * widget pixels.
*/
- void resizePrescaledImage( QSize newSize, QSize oldSize );
+ void resizePrescaledImage( QSize newSize );
/**
* Set the current monitor profile
*/
- void setMonitorProfile( KoColorProfile * profile );
+ void setMonitorProfile( const KoColorProfile * profile );
/**
* Set the current HDR exposure
@@ -175,17 +191,43 @@
*/
void showCurrentMask( bool showMask );
+
+
signals:
/**
* emitted whenever the prescaled image is ready for painting.
* This can happen in two stages: a coarse first stage and a
* smooth second stage.
+ *
+ * @param rc the updated area in image pixels
*/
void sigPrescaledProjectionUpdated( const QRect & rc );
+private slots:
+
+ /**
+ * The timer has fired, and we're going to smoothly scale the
+ * entire rect that's been aggregated, in the main thread (for
+ * now).
+ */
+ void slotDoSmoothScale();
+
private:
+ friend class KisPrescaledProjectionTest;
+
+ void setSettingsForTests(bool updateAllQPainterCanvas,
+ bool useDeferredSmoothing,
+ bool useNearestNeighbour,
+ bool useQtScaling,
+ bool useSampling,
+ bool smoothBetween100And200Percent,
+ bool drawCheckers,
+ bool drawMaskVisualisationOnUnscaledCanvasCache,
+ bool cacheKisImageAsQImage,
+ bool showMask);
+
KisPrescaledProjection( const KisPrescaledProjection & );
KisPrescaledProjection operator=( const KisPrescaledProjection & );
@@ -194,18 +236,28 @@
*
* @param rc The desired rect in KisImage pixels
* @param gc The painter we draw on
+ * @param isDeferredAction we're in the smoothing cycle, so go
+ * directly to the blitz code
*/
- void drawScaledImage( const QRect & rc, QPainter & gc );
+ void drawScaledImage( const QRect & rc, QPainter & gc, bool isDeferredAction = \
false );
/**
- * Return the intersection of the widget size and the given rect
- * in image pixels converted to widget pixels.
+ * Return the aligned rect in image pixels.
*/
- QRect viewRectFromImagePixels( const QRect & imageRect );
+ QRect imageRectFromViewPortPixels( const QRect & viewportRect );
+ /**
+ * Update the internal unscaled canvas cache from the kisimage, if
+ * the settings allow that.
+ *
+ * @param imageRect the rect to be updated in image pixels
+ */
+ void updateUnscaledCache( const QRect & imageRect);
+
struct Private;
Private * const m_d;
};
+
#endif
["signature.asc" (application/pgp-signature)]
_______________________________________________
kimageshop mailing list
kimageshop@kde.org
https://mail.kde.org/mailman/listinfo/kimageshop
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic