Commit 2a1987a8 authored by Eugene Ingerman's avatar Eugene Ingerman

Add antialiasing to createThumbnailDevice

Summary:
1. Added oversampling/antialising to createThumbnailDevice. Interpolation is done using KisTransformWorker with bilinear interpolation. Added parameter that controls oversampling ratio.
2. Added benchmark for new thumbnail code. Results for 6Kx8K image turned into 640px thumbnail see below. About 2x hit in time for 2x oversampling. Quality with 2x oversampling is much better than no oversampling. 4x oversampling slightly better, but not dramatically. See below.
3. Changed oversampling for overview widget to 2x.
4. Fixed caching of oversampled thumbnails.
5. Fixed up functions calls to createThumbnail.

{F156583}
No Oversampling

{F156585}
2x Oversampling

{F156586}
4x Oversampling

PASS   : KisThumbnailBenchmark::benchmarkCreateThumbnail()
RESULT : KisThumbnailBenchmark::benchmarkCreateThumbnail():
     161 msecs per iteration (total: 161, iterations: 1)
PASS   : KisThumbnailBenchmark::benchmarkCreateThumbnailCached()
RESULT : KisThumbnailBenchmark::benchmarkCreateThumbnailCached():
     0.000059 msecs per iteration (total: 62, iterations: 1048576)
PASS   : KisThumbnailBenchmark::benchmarkCreateThumbnailHiQ()
RESULT : KisThumbnailBenchmark::benchmarkCreateThumbnailHiQ():
     3,962 msecs per iteration (total: 3,962, iterations: 1)
PASS   : KisThumbnailBenchmark::benchmarkCreateThumbnailHiQcreateThumbOversample2x()
RESULT : KisThumbnailBenchmark::benchmarkCreateThumbnailHiQcreateThumbOversample2x():
     269 msecs per iteration (total: 269, iterations: 1)
PASS   : KisThumbnailBenchmark::benchmarkCreateThumbnailHiQcreateThumbOversample3x()
RESULT : KisThumbnailBenchmark::benchmarkCreateThumbnailHiQcreateThumbOversample3x():
     489 msecs per iteration (total: 489, iterations: 1)
PASS   : KisThumbnailBenchmark::benchmarkCreateThumbnailHiQcreateThumbOversample4x()
RESULT : KisThumbnailBenchmark::benchmarkCreateThumbnailHiQcreateThumbOversample4x():
     701 msecs per iteration (total: 701, iterations: 1)

Test Plan: Run KisThumbnailBenchmark.

Reviewers: rempt, dkazakov, woltherav

Reviewed By: rempt, woltherav

Subscribers: woltherav

Differential Revision: https://phabricator.kde.org/D1979
parent 2b0c5372
...@@ -38,6 +38,7 @@ set(kis_mask_generator_benchmark_SRCS kis_mask_generator_benchmark.cpp) ...@@ -38,6 +38,7 @@ set(kis_mask_generator_benchmark_SRCS kis_mask_generator_benchmark.cpp)
set(kis_low_memory_benchmark_SRCS kis_low_memory_benchmark.cpp) set(kis_low_memory_benchmark_SRCS kis_low_memory_benchmark.cpp)
set(kis_filter_selections_benchmark_SRCS kis_filter_selections_benchmark.cpp) set(kis_filter_selections_benchmark_SRCS kis_filter_selections_benchmark.cpp)
set(kis_composition_benchmark_SRCS kis_composition_benchmark.cpp) set(kis_composition_benchmark_SRCS kis_composition_benchmark.cpp)
set(kis_thumbnail_benchmark_SRCS kis_thumbnail_benchmark.cpp)
krita_add_benchmark(KisDatamanagerBenchmark TESTNAME krita-benchmarks-KisDataManager ${kis_datamanager_benchmark_SRCS}) krita_add_benchmark(KisDatamanagerBenchmark TESTNAME krita-benchmarks-KisDataManager ${kis_datamanager_benchmark_SRCS})
krita_add_benchmark(KisHLineIteratorBenchmark TESTNAME krita-benchmarks-KisHLineIterator ${kis_hiterator_benchmark_SRCS}) krita_add_benchmark(KisHLineIteratorBenchmark TESTNAME krita-benchmarks-KisHLineIterator ${kis_hiterator_benchmark_SRCS})
...@@ -56,6 +57,7 @@ krita_add_benchmark(KisMaskGeneratorBenchmark TESTNAME krita-benchmarks-KisMaskG ...@@ -56,6 +57,7 @@ krita_add_benchmark(KisMaskGeneratorBenchmark TESTNAME krita-benchmarks-KisMaskG
krita_add_benchmark(KisLowMemoryBenchmark TESTNAME krita-benchmarks-KisLowMemory ${kis_low_memory_benchmark_SRCS}) krita_add_benchmark(KisLowMemoryBenchmark TESTNAME krita-benchmarks-KisLowMemory ${kis_low_memory_benchmark_SRCS})
krita_add_benchmark(KisFilterSelectionsBenchmark TESTNAME krita-image-KisFilterSelectionsBenchmark ${kis_filter_selections_benchmark_SRCS}) krita_add_benchmark(KisFilterSelectionsBenchmark TESTNAME krita-image-KisFilterSelectionsBenchmark ${kis_filter_selections_benchmark_SRCS})
krita_add_benchmark(KisCompositionBenchmark TESTNAME krita-benchmarks-KisComposition ${kis_composition_benchmark_SRCS}) krita_add_benchmark(KisCompositionBenchmark TESTNAME krita-benchmarks-KisComposition ${kis_composition_benchmark_SRCS})
krita_add_benchmark(KisThumbnailBenchmark TESTNAME krita-benchmarks-KisThumbnail ${kis_thumbnail_benchmark_SRCS})
target_link_libraries(KisDatamanagerBenchmark kritaimage Qt5::Test) target_link_libraries(KisDatamanagerBenchmark kritaimage Qt5::Test)
target_link_libraries(KisHLineIteratorBenchmark kritaimage Qt5::Test) target_link_libraries(KisHLineIteratorBenchmark kritaimage Qt5::Test)
...@@ -77,3 +79,5 @@ if(HAVE_VC) ...@@ -77,3 +79,5 @@ if(HAVE_VC)
set_property(TARGET KisCompositionBenchmark APPEND PROPERTY COMPILE_OPTIONS "${Vc_ARCHITECTURE_FLAGS}") set_property(TARGET KisCompositionBenchmark APPEND PROPERTY COMPILE_OPTIONS "${Vc_ARCHITECTURE_FLAGS}")
endif() endif()
target_link_libraries(KisMaskGeneratorBenchmark kritaimage Qt5::Test) target_link_libraries(KisMaskGeneratorBenchmark kritaimage Qt5::Test)
target_link_libraries(KisThumbnailBenchmark kritaimage Qt5::Test)
/*
* Copyright (c) 2016 Eugene Ingerman geneing at gmail dot com
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_thumbnail_benchmark.h"
#include "kis_benchmark_values.h"
#include <QTest>
#include <QImage>
#include "kis_iterator_ng.h"
#include "kis_paint_device.h"
#include "KoColorSpace.h"
#include "KoColorSpaceRegistry.h"
#include "KoCompositeOpRegistry.h"
#include "KoColor.h"
#include "kis_image.h"
#include "kis_painter.h"
#include "kis_types.h"
#include "kis_sequential_iterator.h"
#include "kis_transform_worker.h"
#include <cmath>
#define SAVE_OUTPUT
const int THUMBNAIL_WIDTH = 64;
const int THUMBNAIL_HEIGHT = 64;
const int IMAGE_WIDTH = 8000;
const int IMAGE_HEIGHT = 6000;
const int OVERSAMPLE = 4;
void KisThumbnailBenchmark::initTestCase()
{
m_colorSpace = KoColorSpaceRegistry::instance()->rgb8();
m_dev = new KisPaintDevice(m_colorSpace);
KoColor color(m_colorSpace);
color.fromQColor(Qt::white);
m_dev->clear();
m_dev->fill(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, color.data());
color.fromQColor(Qt::black);
KisPainter painter(m_dev);
painter.setPaintColor(color);
float radius = std::min(IMAGE_WIDTH, IMAGE_HEIGHT);
const float angle = 2 * 3.1415926 / 360.;
const float endWidth = 30;
for (float i = 0; i < 90; i += 5) {
painter.drawThickLine(QPointF(0, 0), QPointF(radius * std::sin(angle * i), radius * std::cos(angle * i)), 1, endWidth);
painter.drawThickLine(QPointF(IMAGE_WIDTH, IMAGE_HEIGHT),
QPointF(IMAGE_WIDTH - radius * std::sin(angle * i), IMAGE_HEIGHT - radius * std::cos(angle * i)), 1, endWidth);
}
#ifdef SAVE_OUTPUT
m_dev->convertToQImage(m_colorSpace->profile()).save("ThumbFullImage.png");
#endif
}
void KisThumbnailBenchmark::cleanupTestCase()
{
}
void KisThumbnailBenchmark::benchmarkCreateThumbnail()
{
QImage image;
QBENCHMARK{
image = m_dev->createThumbnail(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, QRect() );
//m_dev->setDirty();
}
image.save("createThumbnail.png");
}
void KisThumbnailBenchmark::benchmarkCreateThumbnailCached()
{
QImage image;
QBENCHMARK{
image = m_dev->createThumbnail(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, 2. );
}
}
void KisThumbnailBenchmark::benchmarkCreateThumbnailHiQ()
{
QImage image;
QBENCHMARK{
image = m_dev->createThumbnail(OVERSAMPLE * THUMBNAIL_WIDTH, OVERSAMPLE * THUMBNAIL_HEIGHT);
image = image.scaled(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, Qt::KeepAspectRatio, Qt::SmoothTransformation);
m_dev->setDirty();
}
image.save("createThumbnailHiQ.png");
}
void KisThumbnailBenchmark::benchmarkCreateThumbnailHiQcreateThumbOversample2x()
{
QImage image;
QBENCHMARK{
image = m_dev->createThumbnail(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, QRect(), 2,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
m_dev->setDirty();
}
image.save("createThumbnailHiQcreateThumbOversample2x.png");
}
void KisThumbnailBenchmark::benchmarkCreateThumbnailHiQcreateThumbOversample3x()
{
QImage image;
QBENCHMARK{
image = m_dev->createThumbnail(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, QRect(), 3,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
m_dev->setDirty();
}
image.save("createThumbnailHiQcreateThumbOversample3x.png");
}
void KisThumbnailBenchmark::benchmarkCreateThumbnailHiQcreateThumbOversample4x()
{
QImage image;
QBENCHMARK{
image = m_dev->createThumbnail(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, QRect(), 4,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
m_dev->setDirty();
}
image.save("createThumbnailHiQcreateThumbOversample4x.png");
}
QTEST_MAIN(KisThumbnailBenchmark)
/*
* Copyright (c) 2016 Eugene Ingerman geneing at gmail dot com
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_THUMBNAIL_BENCHMARK_H
#define KIS_THUMBNAIL_BENCHMARK_H
#include <QtTest>
#include "kis_paint_device.h"
class KoColor;
class KoColorSpace;
class KisThumbnailBenchmark : public QObject
{
Q_OBJECT
private:
const KoColorSpace * m_colorSpace;
KisPaintDeviceSP m_dev;
QVector<QImage> m_thumbnails;
QSize m_thumbnailSizeLimit;
int m_oversampleRatio;
int m_skipCount;
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void benchmarkCreateThumbnail();
void benchmarkCreateThumbnailCached();
void benchmarkCreateThumbnailHiQ();
void benchmarkCreateThumbnailHiQcreateThumbOversample2x();
void benchmarkCreateThumbnailHiQcreateThumbOversample3x();
void benchmarkCreateThumbnailHiQcreateThumbOversample4x();
};
#endif
...@@ -48,8 +48,8 @@ struct KisIdleWatcher::Private ...@@ -48,8 +48,8 @@ struct KisIdleWatcher::Private
}; };
KisIdleWatcher::KisIdleWatcher(int delay) KisIdleWatcher::KisIdleWatcher(int delay, QObject *parent)
: m_d(new Private(delay)) : QObject(parent), m_d(new Private(delay))
{ {
connect(&m_d->imageModifiedCompressor, SIGNAL(timeout()), SLOT(startIdleCheck())); connect(&m_d->imageModifiedCompressor, SIGNAL(timeout()), SLOT(startIdleCheck()));
connect(&m_d->idleCheckTimer, SIGNAL(timeout()), SLOT(slotIdleCheckTick())); connect(&m_d->idleCheckTimer, SIGNAL(timeout()), SLOT(slotIdleCheckTick()));
......
...@@ -32,7 +32,7 @@ class KRITAIMAGE_EXPORT KisIdleWatcher : public QObject ...@@ -32,7 +32,7 @@ class KRITAIMAGE_EXPORT KisIdleWatcher : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
KisIdleWatcher(int delay); KisIdleWatcher(int delay, QObject* parent = 0);
~KisIdleWatcher(); ~KisIdleWatcher();
bool isIdle() const; bool isIdle() const;
...@@ -40,6 +40,8 @@ public: ...@@ -40,6 +40,8 @@ public:
void setTrackedImages(const QVector<KisImageSP> &images); void setTrackedImages(const QVector<KisImageSP> &images);
void setTrackedImage(KisImageSP image); void setTrackedImage(KisImageSP image);
//Force to image modified state and start countdown to event
void startCountdown(void) { slotImageModified(); }
Q_SIGNALS: Q_SIGNALS:
void startedIdleMode(); void startedIdleMode();
......
...@@ -788,7 +788,7 @@ QImage KisLayer::createThumbnail(qint32 w, qint32 h) ...@@ -788,7 +788,7 @@ QImage KisLayer::createThumbnail(qint32 w, qint32 h)
KisPaintDeviceSP originalDevice = original(); KisPaintDeviceSP originalDevice = original();
return originalDevice ? return originalDevice ?
originalDevice->createThumbnail(w, h, originalDevice->createThumbnail(w, h, 1,
KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags()) : QImage(); KoColorConversionTransformation::internalConversionFlags()) : QImage();
} }
......
...@@ -343,7 +343,7 @@ QImage KisMask::createThumbnail(qint32 w, qint32 h) ...@@ -343,7 +343,7 @@ QImage KisMask::createThumbnail(qint32 w, qint32 h)
selection() ? selection()->projection() : 0; selection() ? selection()->projection() : 0;
return originalDevice ? return originalDevice ?
originalDevice->createThumbnail(w, h, originalDevice->createThumbnail(w, h, 1,
KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags()) : QImage(); KoColorConversionTransformation::internalConversionFlags()) : QImage();
} }
......
This diff is collapsed.
...@@ -63,8 +63,8 @@ typedef KisSharedPtr<KisDataManager> KisDataManagerSP; ...@@ -63,8 +63,8 @@ typedef KisSharedPtr<KisDataManager> KisDataManagerSP;
* when pixels are accessed by an iterator. * when pixels are accessed by an iterator.
*/ */
class KRITAIMAGE_EXPORT KisPaintDevice class KRITAIMAGE_EXPORT KisPaintDevice
: public QObject : public QObject
, public KisShared , public KisShared
{ {
Q_OBJECT Q_OBJECT
...@@ -513,8 +513,8 @@ public: ...@@ -513,8 +513,8 @@ public:
* like sRGB). * like sRGB).
*/ */
QImage convertToQImage(const KoColorProfile * dstProfile, QImage convertToQImage(const KoColorProfile * dstProfile,
KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()) const; KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()) const;
/** /**
* Creates a paint device thumbnail of the paint device, retaining * Creates a paint device thumbnail of the paint device, retaining
...@@ -526,7 +526,8 @@ public: ...@@ -526,7 +526,8 @@ public:
* @param rect: only this rect will be used for the thumbnail * @param rect: only this rect will be used for the thumbnail
* *
*/ */
KisPaintDeviceSP createThumbnailDevice(qint32 w, qint32 h, QRect rect = QRect()) const; KisPaintDeviceSP createThumbnailDevice(qint32 w, qint32 h, QRect rect = QRect(), QRect outputRect = QRect()) const;
KisPaintDeviceSP createThumbnailDeviceOversampled(qint32 w, qint32 h, qreal oversample, QRect rect = QRect(), QRect outputRect = QRect()) const;
/** /**
* Creates a thumbnail of the paint device, retaining the aspect ratio. * Creates a thumbnail of the paint device, retaining the aspect ratio.
...@@ -536,17 +537,18 @@ public: ...@@ -536,17 +537,18 @@ public:
* @param maxw: maximum width * @param maxw: maximum width
* @param maxh: maximum height * @param maxh: maximum height
* @param rect: only this rect will be used for the thumbnail * @param rect: only this rect will be used for the thumbnail
* @param oversample: ratio used for antialiasing
*/ */
QImage createThumbnail(qint32 maxw, qint32 maxh, QRect rect, QImage createThumbnail(qint32 maxw, qint32 maxh, QRect rect, qreal oversample = 1,
KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()); KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags());
/** /**
* Cached version of createThumbnail(qint32 maxw, qint32 maxh, const KisSelection *selection, QRect rect) * Cached version of createThumbnail(qint32 maxw, qint32 maxh, const KisSelection *selection, QRect rect)
*/ */
QImage createThumbnail(qint32 maxw, qint32 maxh, QImage createThumbnail(qint32 maxw, qint32 maxh, qreal oversample = 1,
KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()); KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags());
/** /**
* Fill c and opacity with the values found at x and y. * Fill c and opacity with the values found at x and y.
...@@ -796,8 +798,7 @@ public: ...@@ -796,8 +798,7 @@ public:
QRect calculateExactBounds(bool nonDefaultOnly) const; QRect calculateExactBounds(bool nonDefaultOnly) const;
public: public:
struct MemoryReleaseObject : public QObject struct MemoryReleaseObject : public QObject {
{
~MemoryReleaseObject(); ~MemoryReleaseObject();
}; };
......
...@@ -82,11 +82,11 @@ public: ...@@ -82,11 +82,11 @@ public:
return m_regionCache.getValue(); return m_regionCache.getValue();
} }
QImage createThumbnail(qint32 w, qint32 h, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) { QImage createThumbnail(qint32 w, qint32 h, qreal oversample, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) {
QImage thumbnail; QImage thumbnail;
if(m_thumbnailsValid) { if(m_thumbnailsValid) {
thumbnail = findThumbnail(w, h); thumbnail = findThumbnail(w, h, oversample);
} }
else { else {
m_thumbnails.clear(); m_thumbnails.clear();
...@@ -94,8 +94,8 @@ public: ...@@ -94,8 +94,8 @@ public:
} }
if(thumbnail.isNull()) { if(thumbnail.isNull()) {
thumbnail = m_paintDevice->createThumbnail(w, h, QRect(), renderingIntent, conversionFlags); thumbnail = m_paintDevice->createThumbnail(w, h, QRect(), oversample, renderingIntent, conversionFlags);
cacheThumbnail(w, h, thumbnail); cacheThumbnail(w, h, oversample, thumbnail);
} }
Q_ASSERT(!thumbnail.isNull() || m_paintDevice->extent().isEmpty()); Q_ASSERT(!thumbnail.isNull() || m_paintDevice->extent().isEmpty());
...@@ -103,16 +103,16 @@ public: ...@@ -103,16 +103,16 @@ public:
} }
private: private:
inline QImage findThumbnail(qint32 w, qint32 h) { inline QImage findThumbnail(qint32 w, qint32 h, qreal oversample) {
QImage resultImage; QImage resultImage;
if (m_thumbnails.contains(w) && m_thumbnails[w].contains(h)) { if (m_thumbnails.contains(w) && m_thumbnails[w].contains(h) && m_thumbnails[w][h].contains(oversample)) {
resultImage = m_thumbnails[w][h]; resultImage = m_thumbnails[w][h][oversample];
} }
return resultImage; return resultImage;
} }
inline void cacheThumbnail(qint32 w, qint32 h, QImage image) { inline void cacheThumbnail(qint32 w, qint32 h, qreal oversample, QImage image) {
m_thumbnails[w][h] = image; m_thumbnails[w][h][oversample] = image;
} }
private: private:
...@@ -153,7 +153,7 @@ private: ...@@ -153,7 +153,7 @@ private:
RegionCache m_regionCache; RegionCache m_regionCache;
bool m_thumbnailsValid; bool m_thumbnailsValid;
QMap<int, QMap<int, QImage> > m_thumbnails; QMap<int, QMap<int, QMap<qreal,QImage> > > m_thumbnails;
}; };
#endif /* __KIS_PAINT_DEVICE_CACHE_H */ #endif /* __KIS_PAINT_DEVICE_CACHE_H */
...@@ -285,7 +285,7 @@ QImage KisSelectionBasedLayer::createThumbnail(qint32 w, qint32 h) ...@@ -285,7 +285,7 @@ QImage KisSelectionBasedLayer::createThumbnail(qint32 w, qint32 h)
KisPaintDeviceSP originalDevice = original(); KisPaintDeviceSP originalDevice = original();
return originalDevice && originalSelection ? return originalDevice && originalSelection ?
originalDevice->createThumbnail(w, h, originalDevice->createThumbnail(w, h, 1,
KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags()) : KoColorConversionTransformation::internalConversionFlags()) :
QImage(); QImage();
......
...@@ -224,7 +224,7 @@ void KisUpdateTimeMonitor::reportJobFinished(void *key, const QVector<QRect> &re ...@@ -224,7 +224,7 @@ void KisUpdateTimeMonitor::reportJobFinished(void *key, const QVector<QRect> &re
QMutexLocker locker(&m_d->mutex); QMutexLocker locker(&m_d->mutex);
StrokeTicket *ticket = m_d->preliminaryTickets.take(key); StrokeTicket *ticket = m_d->preliminaryTickets.take(key);
if (ticket) { if( ticket ){
ticket->jobCompleted(); ticket->jobCompleted();
Q_FOREACH (const QRect &rect, rects) { Q_FOREACH (const QRect &rect, rects) {
......
...@@ -167,7 +167,7 @@ void KisCustomPattern::createPattern() ...@@ -167,7 +167,7 @@ void KisCustomPattern::createPattern()
} }
QString dir = KoResourceServerProvider::instance()->patternServer()->saveLocation(); QString dir = KoResourceServerProvider::instance()->patternServer()->saveLocation();
m_pattern = new KoPattern(dev->createThumbnail(size.width(), size.height(), rc, m_pattern = new KoPattern(dev->createThumbnail(size.width(), size.height(), rc, /*oversample*/ 1,
KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags()), name, dir); KoColorConversionTransformation::internalConversionFlags()), name, dir);
} }
......
...@@ -21,4 +21,4 @@ add_subdirectory(colorslider) ...@@ -21,4 +21,4 @@ add_subdirectory(colorslider)
add_subdirectory(animation) add_subdirectory(animation)
add_subdirectory(presethistory) add_subdirectory(presethistory)
add_subdirectory(shapedockers) add_subdirectory(shapedockers)
#add_subdirectory(histogram) add_subdirectory(histogram)
...@@ -131,7 +131,7 @@ void KisCommonColors::recalculate() ...@@ -131,7 +131,7 @@ void KisCommonColors::recalculate()
KisImageWSP kisImage = m_canvas->image(); KisImageWSP kisImage = m_canvas->image();
QImage image = kisImage->projection()->createThumbnail(1024, 1024, kisImage->bounds(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); QImage image = kisImage->projection()->createThumbnail(1024, 1024, kisImage->bounds(), 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
KisCommonColorsRecalculationRunner* runner = new KisCommonColorsRecalculationRunner(image, patchCount(), this); KisCommonColorsRecalculationRunner* runner = new KisCommonColorsRecalculationRunner(image, patchCount(), this);
QThreadPool::globalInstance()->start(runner); QThreadPool::globalInstance()->start(runner);
......
...@@ -32,37 +32,90 @@ ...@@ -32,37 +32,90 @@
#include <kis_group_layer.h> #include <kis_group_layer.h>
#include <kis_layer.h> #include <kis_layer.h>
#include <kis_paint_device.h> #include <kis_paint_device.h>
#include "kis_signal_compressor.h"
#include <KisView.h> #include <KisView.h>
#include <kis_idle_watcher.h>
ChannelDockerDock::ChannelDockerDock( ) : QDockWidget(i18n("Channels")), m_canvas(0) ChannelDockerDock::ChannelDockerDock( ) :
QDockWidget(i18n("Channels")),
m_imageIdleWatcher(new KisIdleWatcher(250, this)),
m_canvas(0)
{ {
m_channelTable = new QTableView(this); m_channelTable = new QTableView(this);
m_model = new ChannelModel(this); m_model = new ChannelModel(this);
m_channelTable->setModel(m_model); m_channelTable->setModel(m_model);
m_channelTable->setShowGrid(false); m_channelTable->setShowGrid(false);
m_channelTable->horizontalHeader()->setStretchLastSection(true);
m_channelTable->verticalHeader()->setVisible(false); m_channelTable->verticalHeader()->setVisible(false);
m_channelTable->horizontalHeader()->setVisible(false);
m_channelTable->setSelectionBehavior( QAbstractItemView::SelectRows );
setWidget(m_channelTable); setWidget(m_channelTable);
connect(m_channelTable,&QTableView::activated, m_model, &ChannelModel::rowActivated);
} }
void ChannelDockerDock::setCanvas(KoCanvasBase * canvas) void ChannelDockerDock::setCanvas(KoCanvasBase * canvas)
{ {
if(m_canvas == canvas)
return;
setEnabled(canvas != 0); setEnabled(canvas != 0);
if (m_canvas) {
m_canvas->disconnectCanvasObserver(this);
m_canvas->image()->disconnect(this);
}
if (!canvas) { if (!canvas) {
m_canvas = 0; m_canvas = 0;
return; return;
} }
m_canvas = dynamic_cast<KisCanvas2*>(canvas); m_canvas = dynamic_cast<KisCanvas2*>(canvas);
if (m_canvas && m_canvas->imageView() && m_canvas->imageView()->image()) { if ( m_canvas && m_canvas->image() ) {
QPointer<KisView> view = m_canvas->imageView(); m_model->slotSetCanvas(m_canvas);
m_model->slotLayerActivated(view->image()->rootLayer());
KisPaintDeviceSP dev = view->image()->projection(); KisPaintDeviceSP dev = m_canvas->image()->projection();
m_imageIdleWatcher->setTrackedImage(m_canvas->image());
connect(m_imageIdleWatcher, &KisIdleWatcher::startedIdleMode, this, &ChannelDockerDock::updateChannelTable);
connect(dev, SIGNAL(colorSpaceChanged(const KoColorSpace*)), m_model, SLOT(slotColorSpaceChanged(const KoColorSpace*))); connect(dev, SIGNAL(colorSpaceChanged(const KoColorSpace*)), m_model, SLOT(slotColorSpaceChanged(const KoColorSpace*)));
connect(dev, SIGNAL(colorSpaceChanged(const KoColorSpace*)), m_canvas, SLOT(channelSelectionChanged())); connect(dev, SIGNAL(colorSpaceChanged(const KoColorSpace*)), m_canvas, SLOT(channelSelectionChanged()));
connect(m_model, SIGNAL(channelFlagsChanged()), m_canvas, SLOT(channelSelectionChanged()));
m_imageIdleWatcher->startCountdown();
} }
connect(m_model, SIGNAL(channelFlagsChanged()), m_canvas, SLOT(channelSelectionChanged()));
} }
void ChannelDockerDock::unsetCanvas()
{
setEnabled(false);
m_canvas = 0;
m_model->unsetCanvas();
}
void ChannelDockerDock::showEvent(QShowEvent *event)
{
Q_UNUSED(event);
m_imageIdleWatcher->startCountdown();
}
void ChannelDockerDock::startUpdateCanvasProjection()
{
m_imageIdleWatcher->startCountdown();
}
void ChannelDockerDock::updateChannelTable()
{
if (isVisible() && m_canvas && m_canvas->image()){
m_model->updateData(m_canvas);
m_channelTable->resizeRowsToContents();
m_channelTable->resizeColumnsToContents();
}
}
...@@ -24,15 +24,28 @@ ...@@ -24,15 +24,28 @@
class ChannelModel; class ChannelModel;
class QTableView; class QTableView;
class KisCanvas2; class KisCanvas2;
class KisSignalCompressor;
class KisIdleWatcher;
class ChannelDockerDock : public QDockWidget, public KoCanvasObserverBase { class ChannelDockerDock : public QDockWidget, public KoCanvasObserverBase {
Q_OBJECT Q_OBJECT
public: public:
ChannelDockerDock(); ChannelDockerDock();
QString observerName() { return "ChannelDockerDock"; } QString observerName() { return "ChannelDockerDock"; }
virtual void setCanvas(KoCanvasBase *canvas); void setCanvas(KoCanvasBase *canvas);
virtual void unsetCanvas() { m_canvas = 0; setEnabled(false);} void unsetCanvas();
void showEvent(QShowEvent *event);
public Q_SLOTS:
void startUpdateCanvasProjection();