Commit 521c2751 authored by Boudewijn Rempt's avatar Boudewijn Rempt

Merge branch 'master' into rempt/T379-resource-management

parents 07a45e59 2747016a
......@@ -231,3 +231,88 @@ void KisGaussianKernel::applyLoG(KisPaintDeviceSP device,
painter.applyMatrix(kernel, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT);
}
Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> KisGaussianKernel::createDilateMatrix(qreal radius)
{
int kernelSize = 2 * std::ceil(radius) + 1;
Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix(kernelSize, kernelSize);
struct UnionFade {
quint8 value(qreal) const {
return 255;
}
};
const qreal fadeStart = radius - 1.0;
/**
* The kernel size should always be odd, then the position of the
* central pixel can be easily calculated
*/
KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1);
const int center = kernelSize / 2;
for (int y = 0; y < kernelSize; y++) {
const qreal yDistance = center - y;
for (int x = 0; x < kernelSize; x++) {
const qreal xDistance = center - x;
const qreal distance = std::sqrt(pow2(xDistance) + pow2(yDistance));
qreal value = 1.0;
if (distance >= radius) {
value = 0.0;
} else if (distance > fadeStart) {
value = radius - distance;
}
matrix(x, y) = value;
}
}
return matrix;
}
void KisGaussianKernel::applyDilate(KisPaintDeviceSP device, const QRect &rect, qreal radius, const QBitArray &channelFlags, KoUpdater *progressUpdater)
{
QPoint srcTopLeft = rect.topLeft();
KisConvolutionPainter painter(device);
painter.setChannelFlags(channelFlags);
painter.setProgress(progressUpdater);
Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix = createDilateMatrix(radius);
KisConvolutionKernelSP kernel =
KisConvolutionKernel::fromMatrix(matrix,
0,
0);
painter.applyMatrix(kernel, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT);
}
#include "kis_sequential_iterator.h"
void KisGaussianKernel::applyErodeU8(KisPaintDeviceSP device, const QRect &rect, qreal radius, const QBitArray &channelFlags, KoUpdater *progressUpdater)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(device->colorSpace()->pixelSize() == 1);
{
KisSequentialIterator dstIt(device, rect);
while (dstIt.nextPixel()) {
quint8 *dstPtr = dstIt.rawData();
*dstPtr = 255 - *dstPtr;
}
}
applyDilate(device, rect, radius, channelFlags, progressUpdater);
{
KisSequentialIterator dstIt(device, rect);
while (dstIt.nextPixel()) {
quint8 *dstPtr = dstIt.rawData();
*dstPtr = 255 - *dstPtr;
}
}
}
......@@ -58,6 +58,20 @@ public:
qreal coeff,
const QBitArray &channelFlags,
KoUpdater *progressUpdater);
static Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> createDilateMatrix(qreal radius);
static void applyDilate(KisPaintDeviceSP device,
const QRect& rect,
qreal radius,
const QBitArray &channelFlags,
KoUpdater *progressUpdater);
static void applyErodeU8(KisPaintDeviceSP device,
const QRect& rect,
qreal radius,
const QBitArray &channelFlags,
KoUpdater *progressUpdater);
};
#endif /* __KIS_GAUSSIAN_KERNEL_H */
......@@ -105,24 +105,6 @@ int KisLayerStyleFilterEnvironment::currentLevelOfDetail() const
m_d->sourceLayer->original()->defaultBounds()->currentLevelOfDetail() : 0;
}
QPainterPath KisLayerStyleFilterEnvironment::layerOutlineCache() const
{
// TODO: make it really cachable!
Q_ASSERT(m_d->sourceLayer);
KisPaintDeviceSP srcDevice = m_d->sourceLayer->projection();
QRect srcRect = srcDevice->exactBounds();
if (srcRect.isEmpty()) return QPainterPath();
KisSelectionSP baseSelection =
KisLsUtils::selectionFromAlphaChannel(srcDevice, srcRect);
KisPixelSelectionSP selection = baseSelection->pixelSelection();
// needs no 'invalidate' call
selection->recalculateOutlineCache();
return selection->outlineCache();
}
void KisLayerStyleFilterEnvironment::setupFinalPainter(KisPainter *gc,
quint8 opacity,
const QBitArray &channelFlags) const
......
......@@ -41,8 +41,6 @@ public:
QRect defaultBounds() const;
int currentLevelOfDetail() const;
QPainterPath layerOutlineCache() const;
void setupFinalPainter(KisPainter *gc,
quint8 opacity,
const QBitArray &channelFlags) const;
......
......@@ -44,22 +44,33 @@
#include "kis_ls_utils.h"
#include "kis_multiple_projection.h"
namespace {
KisLsStrokeFilter::KisLsStrokeFilter()
: KisLayerStyleFilter(KoID("lsstroke", i18n("Stroke (style)")))
int borderSize(psd_stroke_position position, int size)
{
int border = 0;
switch (position) {
case psd_stroke_outside:
border = 2 * size + 1;
break;
case psd_stroke_center:
border = size + 1;
break;
case psd_stroke_inside:
border = 1;
break;
}
return border;
}
}
void paintPathOnSelection(KisPixelSelectionSP selection,
const QPainterPath &path,
const QRect &applyRect,
int size)
KisLsStrokeFilter::KisLsStrokeFilter()
: KisLayerStyleFilter(KoID("lsstroke", i18n("Stroke (style)")))
{
QPen pen(Qt::white, size);
KisPainter gc(selection);
gc.setPaintColor(KoColor(Qt::white, selection->colorSpace()));
gc.drawPainterPath(path, pen, applyRect);
gc.end();
}
void KisLsStrokeFilter::applyStroke(KisPaintDeviceSP srcDevice,
......@@ -70,41 +81,30 @@ void KisLsStrokeFilter::applyStroke(KisPaintDeviceSP srcDevice,
{
if (applyRect.isEmpty()) return;
KisSelectionSP baseSelection = new KisSelection(new KisSelectionEmptyBounds(0));
KisPixelSelectionSP selection = baseSelection->pixelSelection();
//selection->convertToQImage(0, QRect(0,0,300,300)).save("0_selection_initial.png");
QPainterPath strokePath = env->layerOutlineCache();
if (strokePath.isEmpty()) return;
const QRect needRect = kisGrowRect(applyRect, borderSize(config->position(), config->size()));
if (config->position() == psd_stroke_center) {
paintPathOnSelection(selection, strokePath,
applyRect, config->size());
} else if (config->position() == psd_stroke_outside ||
config->position() == psd_stroke_inside) {
paintPathOnSelection(selection, strokePath,
applyRect, 2 * config->size());
KisSelectionSP knockOutSelection =
KisLsUtils::selectionFromAlphaChannel(srcDevice, applyRect);
// disabled intentionally, because it creates artifacts on smooth lines
// KisLsUtils::findEdge(knockOutSelection->pixelSelection(), applyRect, true);
KisSelectionSP baseSelection = KisLsUtils::selectionFromAlphaChannel(srcDevice, needRect);
KisPixelSelectionSP selection = baseSelection->pixelSelection();
if (config->position() == psd_stroke_inside) {
knockOutSelection->pixelSelection()->invert();
{
KisPixelSelectionSP knockOutSelection = new KisPixelSelection(new KisSelectionEmptyBounds(0));
knockOutSelection->makeCloneFromRough(selection, needRect);
if (config->position() == psd_stroke_outside) {
KisGaussianKernel::applyDilate(selection, needRect, 2 * config->size(), QBitArray(), 0);
} else if (config->position() == psd_stroke_inside) {
KisGaussianKernel::applyErodeU8(knockOutSelection, needRect, 2 * config->size(), QBitArray(), 0);
} else if (config->position() == psd_stroke_center) {
KisGaussianKernel::applyDilate(selection, needRect, config->size(), QBitArray(), 0);
KisGaussianKernel::applyErodeU8(knockOutSelection, needRect, config->size(), QBitArray(), 0);
}
KisPainter gc(selection);
gc.setCompositeOp(COMPOSITE_ERASE);
gc.bitBlt(applyRect.topLeft(), knockOutSelection->pixelSelection(), applyRect);
gc.bitBlt(needRect.topLeft(), knockOutSelection, needRect);
gc.end();
}
//selection->convertToQImage(0, QRect(0,0,300,300)).save("1_selection_stroke.png");
KisPaintDeviceSP fillDevice = new KisPaintDevice(srcDevice->colorSpace());
KisLsUtils::fillOverlayDevice(fillDevice, applyRect, config, env);
......@@ -136,19 +136,16 @@ void KisLsStrokeFilter::processDirectly(KisPaintDeviceSP src,
applyStroke(src, dst, applyRect, w.config, env);
}
QRect KisLsStrokeFilter::neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment */*env*/) const
{
Q_UNUSED(style);
return rect;
}
QRect KisLsStrokeFilter::changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const
QRect KisLsStrokeFilter::neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const
{
const psd_layer_effects_stroke *config = style->stroke();
if (!config->effectEnabled()) return rect;
KisLsUtils::LodWrapper<psd_layer_effects_stroke> w(env->currentLevelOfDetail(), config);
return kisGrowRect(rect, borderSize(w.config->position(), w.config->size()));
}
const int borderSize = w.config->size() + 1;
return kisGrowRect(rect, borderSize);
QRect KisLsStrokeFilter::changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const
{
return neededRect(rect, style, env);
}
......@@ -437,4 +437,38 @@ void KisConvolutionPainterTest::testGaussianDetailsFFTW()
testGaussianDetails(true);
}
#include "kis_transaction.h"
void KisConvolutionPainterTest::testDilate()
{
const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8();
KisPaintDeviceSP dev = new KisPaintDevice(cs);
const QRect imageRect(0,0,256,256);
dev->fill(QRect(50,50,100,20), KoColor(Qt::white, cs));
dev->fill(QRect(150,50,20,100), KoColor(Qt::white, cs));
TestUtil::checkQImage(dev->convertToQImage(0, imageRect), "convolution_painter_test", "dilate", "initial");
KisGaussianKernel::applyDilate(dev, imageRect, 10, QBitArray(), 0);
TestUtil::checkQImage(dev->convertToQImage(0, imageRect), "convolution_painter_test", "dilate", "dilate10");
}
void KisConvolutionPainterTest::testErode()
{
const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8();
KisPaintDeviceSP dev = new KisPaintDevice(cs);
const QRect imageRect(0,0,256,256);
dev->fill(QRect(50,50,100,20), KoColor(Qt::white, cs));
dev->fill(QRect(150,50,20,100), KoColor(Qt::white, cs));
TestUtil::checkQImage(dev->convertToQImage(0, imageRect), "convolution_painter_test", "dilate", "initial");
KisGaussianKernel::applyErodeU8(dev, imageRect, 5, QBitArray(), 0);
TestUtil::checkQImage(dev->convertToQImage(0, imageRect), "convolution_painter_test", "dilate", "erode5");
}
QTEST_MAIN(KisConvolutionPainterTest)
......@@ -56,6 +56,9 @@ private Q_SLOTS:
void testGaussianDetailsSpatial();
void testGaussianDetailsFFTW();
void testDilate();
void testErode();
};
#endif
......@@ -60,10 +60,6 @@ ecm_add_test( kis_categorized_list_model_test.cpp modeltest.cpp
TEST_NAME krita-ui-KisCategorizedListModelTest
LINK_LIBRARIES kritaui kritaimage Qt5::Test)
ecm_add_test( kis_resource_server_provider_test.cpp modeltest.cpp
TEST_NAME krita-ui-KisResourceServerProviderTest
LINK_LIBRARIES kritaui kritaimage Qt5::Test)
ecm_add_test( kis_node_juggler_compressed_test.cpp ../../../sdk/tests/testutil.cpp
TEST_NAME krita-image-BaseNodeTest
LINK_LIBRARIES kritaimage kritaui Qt5::Test)
......
/*
* Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org
*
* 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_resource_server_provider_test.h"
#include <QTest>
#include "KisResourceServerProvider.h"
void KisResourceServerProviderTest::testFetchResource()
{
KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
Q_UNUSED(rserver);
// get a known preset by name
// modify it
// get it a second time
// check...
}
QTEST_MAIN(KisResourceServerProviderTest)
/*
* Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org
*
* 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_AUTOGRADIENT_RESOURCE_TEST_H
#define KIS_AUTOGRADIENT_RESOURCE_TEST_H
#include <QtTest>
class KisResourceServerProviderTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testFetchResource();
};
#endif
......@@ -21,6 +21,7 @@ class TenBrushesExtension(krita.Extension):
self.actions = []
self.buttons = []
self.selectedPresets = []
self.oldPreset = None
def setup(self):
self.readSettings()
......@@ -63,7 +64,12 @@ class TenBrushesExtension(krita.Extension):
def activatePreset(self):
allPresets = Application.resources("preset")
if Application.activeWindow() and len(Application.activeWindow().views()) > 0 and self.sender().preset in allPresets:
Application.activeWindow().views()[0].activateResource(allPresets[self.sender().preset])
currentPreset = Application.activeWindow().views()[0].currentBrushPreset()
if self.sender().preset == currentPreset.name():
Application.activeWindow().views()[0].activateResource(self.oldPreset)
else:
self.oldPreset = Application.activeWindow().views()[0].currentBrushPreset()
Application.activeWindow().views()[0].activateResource(allPresets[self.sender().preset])
Scripter.addExtension(TenBrushesExtension(Application))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment